1aef9ec39SRoland Dreier /* 2aef9ec39SRoland Dreier * Copyright (c) 2005 Cisco Systems. All rights reserved. 3aef9ec39SRoland Dreier * 4aef9ec39SRoland Dreier * This software is available to you under a choice of one of two 5aef9ec39SRoland Dreier * licenses. You may choose to be licensed under the terms of the GNU 6aef9ec39SRoland Dreier * General Public License (GPL) Version 2, available from the file 7aef9ec39SRoland Dreier * COPYING in the main directory of this source tree, or the 8aef9ec39SRoland Dreier * OpenIB.org BSD license below: 9aef9ec39SRoland Dreier * 10aef9ec39SRoland Dreier * Redistribution and use in source and binary forms, with or 11aef9ec39SRoland Dreier * without modification, are permitted provided that the following 12aef9ec39SRoland Dreier * conditions are met: 13aef9ec39SRoland Dreier * 14aef9ec39SRoland Dreier * - Redistributions of source code must retain the above 15aef9ec39SRoland Dreier * copyright notice, this list of conditions and the following 16aef9ec39SRoland Dreier * disclaimer. 17aef9ec39SRoland Dreier * 18aef9ec39SRoland Dreier * - Redistributions in binary form must reproduce the above 19aef9ec39SRoland Dreier * copyright notice, this list of conditions and the following 20aef9ec39SRoland Dreier * disclaimer in the documentation and/or other materials 21aef9ec39SRoland Dreier * provided with the distribution. 22aef9ec39SRoland Dreier * 23aef9ec39SRoland Dreier * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24aef9ec39SRoland Dreier * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25aef9ec39SRoland Dreier * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26aef9ec39SRoland Dreier * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27aef9ec39SRoland Dreier * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28aef9ec39SRoland Dreier * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29aef9ec39SRoland Dreier * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30aef9ec39SRoland Dreier * SOFTWARE. 31aef9ec39SRoland Dreier */ 32aef9ec39SRoland Dreier 33d236cd0eSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 34e0bda7d8SBart Van Assche 35aef9ec39SRoland Dreier #include <linux/module.h> 36aef9ec39SRoland Dreier #include <linux/init.h> 37aef9ec39SRoland Dreier #include <linux/slab.h> 38aef9ec39SRoland Dreier #include <linux/err.h> 39aef9ec39SRoland Dreier #include <linux/string.h> 40aef9ec39SRoland Dreier #include <linux/parser.h> 41aef9ec39SRoland Dreier #include <linux/random.h> 42de25968cSTim Schmielau #include <linux/jiffies.h> 4393c76dbbSBart Van Assche #include <linux/lockdep.h> 4419f31343SBart Van Assche #include <linux/inet.h> 4556b5390cSBart Van Assche #include <rdma/ib_cache.h> 46aef9ec39SRoland Dreier 4760063497SArun Sharma #include <linux/atomic.h> 48aef9ec39SRoland Dreier 49aef9ec39SRoland Dreier #include <scsi/scsi.h> 50aef9ec39SRoland Dreier #include <scsi/scsi_device.h> 51aef9ec39SRoland Dreier #include <scsi/scsi_dbg.h> 5271444b97SJack Wang #include <scsi/scsi_tcq.h> 53aef9ec39SRoland Dreier #include <scsi/srp.h> 543236822bSFUJITA Tomonori #include <scsi/scsi_transport_srp.h> 55aef9ec39SRoland Dreier 56aef9ec39SRoland Dreier #include "ib_srp.h" 57aef9ec39SRoland Dreier 58aef9ec39SRoland Dreier #define DRV_NAME "ib_srp" 59aef9ec39SRoland Dreier #define PFX DRV_NAME ": " 60aef9ec39SRoland Dreier 61aef9ec39SRoland Dreier MODULE_AUTHOR("Roland Dreier"); 6233ab3e5bSBart Van Assche MODULE_DESCRIPTION("InfiniBand SCSI RDMA Protocol initiator"); 63aef9ec39SRoland Dreier MODULE_LICENSE("Dual BSD/GPL"); 64aef9ec39SRoland Dreier 651a1faf7aSBart Van Assche #if !defined(CONFIG_DYNAMIC_DEBUG) 661a1faf7aSBart Van Assche #define DEFINE_DYNAMIC_DEBUG_METADATA(name, fmt) 671a1faf7aSBart Van Assche #define DYNAMIC_DEBUG_BRANCH(descriptor) false 681a1faf7aSBart Van Assche #endif 691a1faf7aSBart Van Assche 7049248644SDavid Dillow static unsigned int srp_sg_tablesize; 7149248644SDavid Dillow static unsigned int cmd_sg_entries; 72c07d424dSDavid Dillow static unsigned int indirect_sg_entries; 73c07d424dSDavid Dillow static bool allow_ext_sg; 7403f6fb93SBart Van Assche static bool prefer_fr = true; 7503f6fb93SBart Van Assche static bool register_always = true; 76c222a39fSBart Van Assche static bool never_register; 77aef9ec39SRoland Dreier static int topspin_workarounds = 1; 78aef9ec39SRoland Dreier 7949248644SDavid Dillow module_param(srp_sg_tablesize, uint, 0444); 8049248644SDavid Dillow MODULE_PARM_DESC(srp_sg_tablesize, "Deprecated name for cmd_sg_entries"); 8149248644SDavid Dillow 8249248644SDavid Dillow module_param(cmd_sg_entries, uint, 0444); 8349248644SDavid Dillow MODULE_PARM_DESC(cmd_sg_entries, 8449248644SDavid Dillow "Default number of gather/scatter entries in the SRP command (default is 12, max 255)"); 8549248644SDavid Dillow 86c07d424dSDavid Dillow module_param(indirect_sg_entries, uint, 0444); 87c07d424dSDavid Dillow MODULE_PARM_DESC(indirect_sg_entries, 8865e8617fSMing Lin "Default max number of gather/scatter entries (default is 12, max is " __stringify(SG_MAX_SEGMENTS) ")"); 89c07d424dSDavid Dillow 90c07d424dSDavid Dillow module_param(allow_ext_sg, bool, 0444); 91c07d424dSDavid Dillow MODULE_PARM_DESC(allow_ext_sg, 92c07d424dSDavid Dillow "Default behavior when there are more than cmd_sg_entries S/G entries after mapping; fails the request when false (default false)"); 93c07d424dSDavid Dillow 94aef9ec39SRoland Dreier module_param(topspin_workarounds, int, 0444); 95aef9ec39SRoland Dreier MODULE_PARM_DESC(topspin_workarounds, 96aef9ec39SRoland Dreier "Enable workarounds for Topspin/Cisco SRP target bugs if != 0"); 97aef9ec39SRoland Dreier 985cfb1782SBart Van Assche module_param(prefer_fr, bool, 0444); 995cfb1782SBart Van Assche MODULE_PARM_DESC(prefer_fr, 1005cfb1782SBart Van Assche "Whether to use fast registration if both FMR and fast registration are supported"); 1015cfb1782SBart Van Assche 102b1b8854dSBart Van Assche module_param(register_always, bool, 0444); 103b1b8854dSBart Van Assche MODULE_PARM_DESC(register_always, 104b1b8854dSBart Van Assche "Use memory registration even for contiguous memory regions"); 105b1b8854dSBart Van Assche 106c222a39fSBart Van Assche module_param(never_register, bool, 0444); 107c222a39fSBart Van Assche MODULE_PARM_DESC(never_register, "Never register memory"); 108c222a39fSBart Van Assche 1099c27847dSLuis R. Rodriguez static const struct kernel_param_ops srp_tmo_ops; 110ed9b2264SBart Van Assche 111a95cadb9SBart Van Assche static int srp_reconnect_delay = 10; 112a95cadb9SBart Van Assche module_param_cb(reconnect_delay, &srp_tmo_ops, &srp_reconnect_delay, 113a95cadb9SBart Van Assche S_IRUGO | S_IWUSR); 114a95cadb9SBart Van Assche MODULE_PARM_DESC(reconnect_delay, "Time between successive reconnect attempts"); 115a95cadb9SBart Van Assche 116ed9b2264SBart Van Assche static int srp_fast_io_fail_tmo = 15; 117ed9b2264SBart Van Assche module_param_cb(fast_io_fail_tmo, &srp_tmo_ops, &srp_fast_io_fail_tmo, 118ed9b2264SBart Van Assche S_IRUGO | S_IWUSR); 119ed9b2264SBart Van Assche MODULE_PARM_DESC(fast_io_fail_tmo, 120ed9b2264SBart Van Assche "Number of seconds between the observation of a transport" 121ed9b2264SBart Van Assche " layer error and failing all I/O. \"off\" means that this" 122ed9b2264SBart Van Assche " functionality is disabled."); 123ed9b2264SBart Van Assche 124a95cadb9SBart Van Assche static int srp_dev_loss_tmo = 600; 125ed9b2264SBart Van Assche module_param_cb(dev_loss_tmo, &srp_tmo_ops, &srp_dev_loss_tmo, 126ed9b2264SBart Van Assche S_IRUGO | S_IWUSR); 127ed9b2264SBart Van Assche MODULE_PARM_DESC(dev_loss_tmo, 128ed9b2264SBart Van Assche "Maximum number of seconds that the SRP transport should" 129ed9b2264SBart Van Assche " insulate transport layer errors. After this time has been" 130ed9b2264SBart Van Assche " exceeded the SCSI host is removed. Should be" 131ed9b2264SBart Van Assche " between 1 and " __stringify(SCSI_DEVICE_BLOCK_MAX_TIMEOUT) 132ed9b2264SBart Van Assche " if fast_io_fail_tmo has not been set. \"off\" means that" 133ed9b2264SBart Van Assche " this functionality is disabled."); 134ed9b2264SBart Van Assche 135882981f4SBart Van Assche static bool srp_use_imm_data = true; 136882981f4SBart Van Assche module_param_named(use_imm_data, srp_use_imm_data, bool, 0644); 137882981f4SBart Van Assche MODULE_PARM_DESC(use_imm_data, 138882981f4SBart Van Assche "Whether or not to request permission to use immediate data during SRP login."); 139882981f4SBart Van Assche 140882981f4SBart Van Assche static unsigned int srp_max_imm_data = 8 * 1024; 141882981f4SBart Van Assche module_param_named(max_imm_data, srp_max_imm_data, uint, 0644); 142882981f4SBart Van Assche MODULE_PARM_DESC(max_imm_data, "Maximum immediate data size."); 143882981f4SBart Van Assche 144d92c0da7SBart Van Assche static unsigned ch_count; 145d92c0da7SBart Van Assche module_param(ch_count, uint, 0444); 146d92c0da7SBart Van Assche MODULE_PARM_DESC(ch_count, 147d92c0da7SBart Van Assche "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."); 148d92c0da7SBart Van Assche 149aef9ec39SRoland Dreier static void srp_add_one(struct ib_device *device); 1507c1eb45aSHaggai Eran static void srp_remove_one(struct ib_device *device, void *client_data); 1511dc7b1f1SChristoph Hellwig static void srp_recv_done(struct ib_cq *cq, struct ib_wc *wc); 1521dc7b1f1SChristoph Hellwig static void srp_handle_qp_err(struct ib_cq *cq, struct ib_wc *wc, 1531dc7b1f1SChristoph Hellwig const char *opname); 154e7ff98aeSParav Pandit static int srp_ib_cm_handler(struct ib_cm_id *cm_id, 155e7ff98aeSParav Pandit const struct ib_cm_event *event); 15619f31343SBart Van Assche static int srp_rdma_cm_handler(struct rdma_cm_id *cm_id, 15719f31343SBart Van Assche struct rdma_cm_event *event); 158aef9ec39SRoland Dreier 1593236822bSFUJITA Tomonori static struct scsi_transport_template *ib_srp_transport_template; 160bcc05910SBart Van Assche static struct workqueue_struct *srp_remove_wq; 1613236822bSFUJITA Tomonori 162aef9ec39SRoland Dreier static struct ib_client srp_client = { 163aef9ec39SRoland Dreier .name = "srp", 164aef9ec39SRoland Dreier .add = srp_add_one, 165aef9ec39SRoland Dreier .remove = srp_remove_one 166aef9ec39SRoland Dreier }; 167aef9ec39SRoland Dreier 168c1a0b23bSMichael S. Tsirkin static struct ib_sa_client srp_sa_client; 169c1a0b23bSMichael S. Tsirkin 170ed9b2264SBart Van Assche static int srp_tmo_get(char *buffer, const struct kernel_param *kp) 171ed9b2264SBart Van Assche { 172ed9b2264SBart Van Assche int tmo = *(int *)kp->arg; 173ed9b2264SBart Van Assche 174ed9b2264SBart Van Assche if (tmo >= 0) 175ed9b2264SBart Van Assche return sprintf(buffer, "%d", tmo); 176ed9b2264SBart Van Assche else 177ed9b2264SBart Van Assche return sprintf(buffer, "off"); 178ed9b2264SBart Van Assche } 179ed9b2264SBart Van Assche 180ed9b2264SBart Van Assche static int srp_tmo_set(const char *val, const struct kernel_param *kp) 181ed9b2264SBart Van Assche { 182ed9b2264SBart Van Assche int tmo, res; 183ed9b2264SBart Van Assche 1843fdf70acSSagi Grimberg res = srp_parse_tmo(&tmo, val); 185ed9b2264SBart Van Assche if (res) 186ed9b2264SBart Van Assche goto out; 1873fdf70acSSagi Grimberg 188a95cadb9SBart Van Assche if (kp->arg == &srp_reconnect_delay) 189a95cadb9SBart Van Assche res = srp_tmo_valid(tmo, srp_fast_io_fail_tmo, 190a95cadb9SBart Van Assche srp_dev_loss_tmo); 191a95cadb9SBart Van Assche else if (kp->arg == &srp_fast_io_fail_tmo) 192a95cadb9SBart Van Assche res = srp_tmo_valid(srp_reconnect_delay, tmo, srp_dev_loss_tmo); 193ed9b2264SBart Van Assche else 194a95cadb9SBart Van Assche res = srp_tmo_valid(srp_reconnect_delay, srp_fast_io_fail_tmo, 195a95cadb9SBart Van Assche tmo); 196ed9b2264SBart Van Assche if (res) 197ed9b2264SBart Van Assche goto out; 198ed9b2264SBart Van Assche *(int *)kp->arg = tmo; 199ed9b2264SBart Van Assche 200ed9b2264SBart Van Assche out: 201ed9b2264SBart Van Assche return res; 202ed9b2264SBart Van Assche } 203ed9b2264SBart Van Assche 2049c27847dSLuis R. Rodriguez static const struct kernel_param_ops srp_tmo_ops = { 205ed9b2264SBart Van Assche .get = srp_tmo_get, 206ed9b2264SBart Van Assche .set = srp_tmo_set, 207ed9b2264SBart Van Assche }; 208ed9b2264SBart Van Assche 209aef9ec39SRoland Dreier static inline struct srp_target_port *host_to_target(struct Scsi_Host *host) 210aef9ec39SRoland Dreier { 211aef9ec39SRoland Dreier return (struct srp_target_port *) host->hostdata; 212aef9ec39SRoland Dreier } 213aef9ec39SRoland Dreier 214aef9ec39SRoland Dreier static const char *srp_target_info(struct Scsi_Host *host) 215aef9ec39SRoland Dreier { 216aef9ec39SRoland Dreier return host_to_target(host)->target_name; 217aef9ec39SRoland Dreier } 218aef9ec39SRoland Dreier 2195d7cbfd6SRoland Dreier static int srp_target_is_topspin(struct srp_target_port *target) 2205d7cbfd6SRoland Dreier { 2215d7cbfd6SRoland Dreier static const u8 topspin_oui[3] = { 0x00, 0x05, 0xad }; 2223d1ff48dSRaghava Kondapalli static const u8 cisco_oui[3] = { 0x00, 0x1b, 0x0d }; 2235d7cbfd6SRoland Dreier 2245d7cbfd6SRoland Dreier return topspin_workarounds && 2253d1ff48dSRaghava Kondapalli (!memcmp(&target->ioc_guid, topspin_oui, sizeof topspin_oui) || 2263d1ff48dSRaghava Kondapalli !memcmp(&target->ioc_guid, cisco_oui, sizeof cisco_oui)); 2275d7cbfd6SRoland Dreier } 2285d7cbfd6SRoland Dreier 229aef9ec39SRoland Dreier static struct srp_iu *srp_alloc_iu(struct srp_host *host, size_t size, 230aef9ec39SRoland Dreier gfp_t gfp_mask, 231aef9ec39SRoland Dreier enum dma_data_direction direction) 232aef9ec39SRoland Dreier { 233aef9ec39SRoland Dreier struct srp_iu *iu; 234aef9ec39SRoland Dreier 235aef9ec39SRoland Dreier iu = kmalloc(sizeof *iu, gfp_mask); 236aef9ec39SRoland Dreier if (!iu) 237aef9ec39SRoland Dreier goto out; 238aef9ec39SRoland Dreier 239aef9ec39SRoland Dreier iu->buf = kzalloc(size, gfp_mask); 240aef9ec39SRoland Dreier if (!iu->buf) 241aef9ec39SRoland Dreier goto out_free_iu; 242aef9ec39SRoland Dreier 24305321937SGreg Kroah-Hartman iu->dma = ib_dma_map_single(host->srp_dev->dev, iu->buf, size, 24405321937SGreg Kroah-Hartman direction); 24505321937SGreg Kroah-Hartman if (ib_dma_mapping_error(host->srp_dev->dev, iu->dma)) 246aef9ec39SRoland Dreier goto out_free_buf; 247aef9ec39SRoland Dreier 248aef9ec39SRoland Dreier iu->size = size; 249aef9ec39SRoland Dreier iu->direction = direction; 250aef9ec39SRoland Dreier 251aef9ec39SRoland Dreier return iu; 252aef9ec39SRoland Dreier 253aef9ec39SRoland Dreier out_free_buf: 254aef9ec39SRoland Dreier kfree(iu->buf); 255aef9ec39SRoland Dreier out_free_iu: 256aef9ec39SRoland Dreier kfree(iu); 257aef9ec39SRoland Dreier out: 258aef9ec39SRoland Dreier return NULL; 259aef9ec39SRoland Dreier } 260aef9ec39SRoland Dreier 261aef9ec39SRoland Dreier static void srp_free_iu(struct srp_host *host, struct srp_iu *iu) 262aef9ec39SRoland Dreier { 263aef9ec39SRoland Dreier if (!iu) 264aef9ec39SRoland Dreier return; 265aef9ec39SRoland Dreier 26605321937SGreg Kroah-Hartman ib_dma_unmap_single(host->srp_dev->dev, iu->dma, iu->size, 26705321937SGreg Kroah-Hartman iu->direction); 268aef9ec39SRoland Dreier kfree(iu->buf); 269aef9ec39SRoland Dreier kfree(iu); 270aef9ec39SRoland Dreier } 271aef9ec39SRoland Dreier 272aef9ec39SRoland Dreier static void srp_qp_event(struct ib_event *event, void *context) 273aef9ec39SRoland Dreier { 27457363d98SSagi Grimberg pr_debug("QP event %s (%d)\n", 27557363d98SSagi Grimberg ib_event_msg(event->event), event->event); 276aef9ec39SRoland Dreier } 277aef9ec39SRoland Dreier 27819f31343SBart Van Assche static int srp_init_ib_qp(struct srp_target_port *target, 279aef9ec39SRoland Dreier struct ib_qp *qp) 280aef9ec39SRoland Dreier { 281aef9ec39SRoland Dreier struct ib_qp_attr *attr; 282aef9ec39SRoland Dreier int ret; 283aef9ec39SRoland Dreier 284aef9ec39SRoland Dreier attr = kmalloc(sizeof *attr, GFP_KERNEL); 285aef9ec39SRoland Dreier if (!attr) 286aef9ec39SRoland Dreier return -ENOMEM; 287aef9ec39SRoland Dreier 28856b5390cSBart Van Assche ret = ib_find_cached_pkey(target->srp_host->srp_dev->dev, 289aef9ec39SRoland Dreier target->srp_host->port, 29019f31343SBart Van Assche be16_to_cpu(target->ib_cm.pkey), 291aef9ec39SRoland Dreier &attr->pkey_index); 292aef9ec39SRoland Dreier if (ret) 293aef9ec39SRoland Dreier goto out; 294aef9ec39SRoland Dreier 295aef9ec39SRoland Dreier attr->qp_state = IB_QPS_INIT; 296aef9ec39SRoland Dreier attr->qp_access_flags = (IB_ACCESS_REMOTE_READ | 297aef9ec39SRoland Dreier IB_ACCESS_REMOTE_WRITE); 298aef9ec39SRoland Dreier attr->port_num = target->srp_host->port; 299aef9ec39SRoland Dreier 300aef9ec39SRoland Dreier ret = ib_modify_qp(qp, attr, 301aef9ec39SRoland Dreier IB_QP_STATE | 302aef9ec39SRoland Dreier IB_QP_PKEY_INDEX | 303aef9ec39SRoland Dreier IB_QP_ACCESS_FLAGS | 304aef9ec39SRoland Dreier IB_QP_PORT); 305aef9ec39SRoland Dreier 306aef9ec39SRoland Dreier out: 307aef9ec39SRoland Dreier kfree(attr); 308aef9ec39SRoland Dreier return ret; 309aef9ec39SRoland Dreier } 310aef9ec39SRoland Dreier 31119f31343SBart Van Assche static int srp_new_ib_cm_id(struct srp_rdma_ch *ch) 3129fe4bcf4SDavid Dillow { 313509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 3149fe4bcf4SDavid Dillow struct ib_cm_id *new_cm_id; 3159fe4bcf4SDavid Dillow 31605321937SGreg Kroah-Hartman new_cm_id = ib_create_cm_id(target->srp_host->srp_dev->dev, 31719f31343SBart Van Assche srp_ib_cm_handler, ch); 3189fe4bcf4SDavid Dillow if (IS_ERR(new_cm_id)) 3199fe4bcf4SDavid Dillow return PTR_ERR(new_cm_id); 3209fe4bcf4SDavid Dillow 32119f31343SBart Van Assche if (ch->ib_cm.cm_id) 32219f31343SBart Van Assche ib_destroy_cm_id(ch->ib_cm.cm_id); 32319f31343SBart Van Assche ch->ib_cm.cm_id = new_cm_id; 3244c33bd19SDasaratharaman Chandramouli if (rdma_cap_opa_ah(target->srp_host->srp_dev->dev, 3254c33bd19SDasaratharaman Chandramouli target->srp_host->port)) 32619f31343SBart Van Assche ch->ib_cm.path.rec_type = SA_PATH_REC_TYPE_OPA; 3274c33bd19SDasaratharaman Chandramouli else 32819f31343SBart Van Assche ch->ib_cm.path.rec_type = SA_PATH_REC_TYPE_IB; 32919f31343SBart Van Assche ch->ib_cm.path.sgid = target->sgid; 33019f31343SBart Van Assche ch->ib_cm.path.dgid = target->ib_cm.orig_dgid; 33119f31343SBart Van Assche ch->ib_cm.path.pkey = target->ib_cm.pkey; 33219f31343SBart Van Assche ch->ib_cm.path.service_id = target->ib_cm.service_id; 3339fe4bcf4SDavid Dillow 3349fe4bcf4SDavid Dillow return 0; 3359fe4bcf4SDavid Dillow } 3369fe4bcf4SDavid Dillow 33719f31343SBart Van Assche static int srp_new_rdma_cm_id(struct srp_rdma_ch *ch) 33819f31343SBart Van Assche { 33919f31343SBart Van Assche struct srp_target_port *target = ch->target; 34019f31343SBart Van Assche struct rdma_cm_id *new_cm_id; 34119f31343SBart Van Assche int ret; 34219f31343SBart Van Assche 34319f31343SBart Van Assche new_cm_id = rdma_create_id(target->net, srp_rdma_cm_handler, ch, 34419f31343SBart Van Assche RDMA_PS_TCP, IB_QPT_RC); 34519f31343SBart Van Assche if (IS_ERR(new_cm_id)) { 34619f31343SBart Van Assche ret = PTR_ERR(new_cm_id); 34719f31343SBart Van Assche new_cm_id = NULL; 34819f31343SBart Van Assche goto out; 34919f31343SBart Van Assche } 35019f31343SBart Van Assche 35119f31343SBart Van Assche init_completion(&ch->done); 35219f31343SBart Van Assche ret = rdma_resolve_addr(new_cm_id, target->rdma_cm.src_specified ? 35319f31343SBart Van Assche (struct sockaddr *)&target->rdma_cm.src : NULL, 35419f31343SBart Van Assche (struct sockaddr *)&target->rdma_cm.dst, 35519f31343SBart Van Assche SRP_PATH_REC_TIMEOUT_MS); 35619f31343SBart Van Assche if (ret) { 3577da09af9SBart Van Assche pr_err("No route available from %pIS to %pIS (%d)\n", 3587da09af9SBart Van Assche &target->rdma_cm.src, &target->rdma_cm.dst, ret); 35919f31343SBart Van Assche goto out; 36019f31343SBart Van Assche } 36119f31343SBart Van Assche ret = wait_for_completion_interruptible(&ch->done); 36219f31343SBart Van Assche if (ret < 0) 36319f31343SBart Van Assche goto out; 36419f31343SBart Van Assche 36519f31343SBart Van Assche ret = ch->status; 36619f31343SBart Van Assche if (ret) { 3677da09af9SBart Van Assche pr_err("Resolving address %pIS failed (%d)\n", 3687da09af9SBart Van Assche &target->rdma_cm.dst, ret); 36919f31343SBart Van Assche goto out; 37019f31343SBart Van Assche } 37119f31343SBart Van Assche 37219f31343SBart Van Assche swap(ch->rdma_cm.cm_id, new_cm_id); 37319f31343SBart Van Assche 37419f31343SBart Van Assche out: 37519f31343SBart Van Assche if (new_cm_id) 37619f31343SBart Van Assche rdma_destroy_id(new_cm_id); 37719f31343SBart Van Assche 37819f31343SBart Van Assche return ret; 37919f31343SBart Van Assche } 38019f31343SBart Van Assche 38119f31343SBart Van Assche static int srp_new_cm_id(struct srp_rdma_ch *ch) 38219f31343SBart Van Assche { 38319f31343SBart Van Assche struct srp_target_port *target = ch->target; 38419f31343SBart Van Assche 38519f31343SBart Van Assche return target->using_rdma_cm ? srp_new_rdma_cm_id(ch) : 38619f31343SBart Van Assche srp_new_ib_cm_id(ch); 38719f31343SBart Van Assche } 38819f31343SBart Van Assche 389d1b4289eSBart Van Assche static struct ib_fmr_pool *srp_alloc_fmr_pool(struct srp_target_port *target) 390d1b4289eSBart Van Assche { 391d1b4289eSBart Van Assche struct srp_device *dev = target->srp_host->srp_dev; 392d1b4289eSBart Van Assche struct ib_fmr_pool_param fmr_param; 393d1b4289eSBart Van Assche 394d1b4289eSBart Van Assche memset(&fmr_param, 0, sizeof(fmr_param)); 395fa9863f8SBart Van Assche fmr_param.pool_size = target->mr_pool_size; 396d1b4289eSBart Van Assche fmr_param.dirty_watermark = fmr_param.pool_size / 4; 397d1b4289eSBart Van Assche fmr_param.cache = 1; 39852ede08fSBart Van Assche fmr_param.max_pages_per_fmr = dev->max_pages_per_mr; 39952ede08fSBart Van Assche fmr_param.page_shift = ilog2(dev->mr_page_size); 400d1b4289eSBart Van Assche fmr_param.access = (IB_ACCESS_LOCAL_WRITE | 401d1b4289eSBart Van Assche IB_ACCESS_REMOTE_WRITE | 402d1b4289eSBart Van Assche IB_ACCESS_REMOTE_READ); 403d1b4289eSBart Van Assche 404d1b4289eSBart Van Assche return ib_create_fmr_pool(dev->pd, &fmr_param); 405d1b4289eSBart Van Assche } 406d1b4289eSBart Van Assche 4075cfb1782SBart Van Assche /** 4085cfb1782SBart Van Assche * srp_destroy_fr_pool() - free the resources owned by a pool 4095cfb1782SBart Van Assche * @pool: Fast registration pool to be destroyed. 4105cfb1782SBart Van Assche */ 4115cfb1782SBart Van Assche static void srp_destroy_fr_pool(struct srp_fr_pool *pool) 4125cfb1782SBart Van Assche { 4135cfb1782SBart Van Assche int i; 4145cfb1782SBart Van Assche struct srp_fr_desc *d; 4155cfb1782SBart Van Assche 4165cfb1782SBart Van Assche if (!pool) 4175cfb1782SBart Van Assche return; 4185cfb1782SBart Van Assche 4195cfb1782SBart Van Assche for (i = 0, d = &pool->desc[0]; i < pool->size; i++, d++) { 4205cfb1782SBart Van Assche if (d->mr) 4215cfb1782SBart Van Assche ib_dereg_mr(d->mr); 4225cfb1782SBart Van Assche } 4235cfb1782SBart Van Assche kfree(pool); 4245cfb1782SBart Van Assche } 4255cfb1782SBart Van Assche 4265cfb1782SBart Van Assche /** 4275cfb1782SBart Van Assche * srp_create_fr_pool() - allocate and initialize a pool for fast registration 4285cfb1782SBart Van Assche * @device: IB device to allocate fast registration descriptors for. 4295cfb1782SBart Van Assche * @pd: Protection domain associated with the FR descriptors. 4305cfb1782SBart Van Assche * @pool_size: Number of descriptors to allocate. 4315cfb1782SBart Van Assche * @max_page_list_len: Maximum fast registration work request page list length. 4325cfb1782SBart Van Assche */ 4335cfb1782SBart Van Assche static struct srp_fr_pool *srp_create_fr_pool(struct ib_device *device, 4345cfb1782SBart Van Assche struct ib_pd *pd, int pool_size, 4355cfb1782SBart Van Assche int max_page_list_len) 4365cfb1782SBart Van Assche { 4375cfb1782SBart Van Assche struct srp_fr_pool *pool; 4385cfb1782SBart Van Assche struct srp_fr_desc *d; 4395cfb1782SBart Van Assche struct ib_mr *mr; 4405cfb1782SBart Van Assche int i, ret = -EINVAL; 441fbd36818SSergey Gorenko enum ib_mr_type mr_type; 4425cfb1782SBart Van Assche 4435cfb1782SBart Van Assche if (pool_size <= 0) 4445cfb1782SBart Van Assche goto err; 4455cfb1782SBart Van Assche ret = -ENOMEM; 4467a7b0feaSGustavo A. R. Silva pool = kzalloc(struct_size(pool, desc, pool_size), GFP_KERNEL); 4475cfb1782SBart Van Assche if (!pool) 4485cfb1782SBart Van Assche goto err; 4495cfb1782SBart Van Assche pool->size = pool_size; 4505cfb1782SBart Van Assche pool->max_page_list_len = max_page_list_len; 4515cfb1782SBart Van Assche spin_lock_init(&pool->lock); 4525cfb1782SBart Van Assche INIT_LIST_HEAD(&pool->free_list); 4535cfb1782SBart Van Assche 454fbd36818SSergey Gorenko if (device->attrs.device_cap_flags & IB_DEVICE_SG_GAPS_REG) 455fbd36818SSergey Gorenko mr_type = IB_MR_TYPE_SG_GAPS; 456fbd36818SSergey Gorenko else 457fbd36818SSergey Gorenko mr_type = IB_MR_TYPE_MEM_REG; 458fbd36818SSergey Gorenko 4595cfb1782SBart Van Assche for (i = 0, d = &pool->desc[0]; i < pool->size; i++, d++) { 460fbd36818SSergey Gorenko mr = ib_alloc_mr(pd, mr_type, max_page_list_len); 4615cfb1782SBart Van Assche if (IS_ERR(mr)) { 4625cfb1782SBart Van Assche ret = PTR_ERR(mr); 4633787d990SBart Van Assche if (ret == -ENOMEM) 4643787d990SBart Van Assche pr_info("%s: ib_alloc_mr() failed. Try to reduce max_cmd_per_lun, max_sect or ch_count\n", 4653787d990SBart Van Assche dev_name(&device->dev)); 4665cfb1782SBart Van Assche goto destroy_pool; 4675cfb1782SBart Van Assche } 4685cfb1782SBart Van Assche d->mr = mr; 4695cfb1782SBart Van Assche list_add_tail(&d->entry, &pool->free_list); 4705cfb1782SBart Van Assche } 4715cfb1782SBart Van Assche 4725cfb1782SBart Van Assche out: 4735cfb1782SBart Van Assche return pool; 4745cfb1782SBart Van Assche 4755cfb1782SBart Van Assche destroy_pool: 4765cfb1782SBart Van Assche srp_destroy_fr_pool(pool); 4775cfb1782SBart Van Assche 4785cfb1782SBart Van Assche err: 4795cfb1782SBart Van Assche pool = ERR_PTR(ret); 4805cfb1782SBart Van Assche goto out; 4815cfb1782SBart Van Assche } 4825cfb1782SBart Van Assche 4835cfb1782SBart Van Assche /** 4845cfb1782SBart Van Assche * srp_fr_pool_get() - obtain a descriptor suitable for fast registration 4855cfb1782SBart Van Assche * @pool: Pool to obtain descriptor from. 4865cfb1782SBart Van Assche */ 4875cfb1782SBart Van Assche static struct srp_fr_desc *srp_fr_pool_get(struct srp_fr_pool *pool) 4885cfb1782SBart Van Assche { 4895cfb1782SBart Van Assche struct srp_fr_desc *d = NULL; 4905cfb1782SBart Van Assche unsigned long flags; 4915cfb1782SBart Van Assche 4925cfb1782SBart Van Assche spin_lock_irqsave(&pool->lock, flags); 4935cfb1782SBart Van Assche if (!list_empty(&pool->free_list)) { 4945cfb1782SBart Van Assche d = list_first_entry(&pool->free_list, typeof(*d), entry); 4955cfb1782SBart Van Assche list_del(&d->entry); 4965cfb1782SBart Van Assche } 4975cfb1782SBart Van Assche spin_unlock_irqrestore(&pool->lock, flags); 4985cfb1782SBart Van Assche 4995cfb1782SBart Van Assche return d; 5005cfb1782SBart Van Assche } 5015cfb1782SBart Van Assche 5025cfb1782SBart Van Assche /** 5035cfb1782SBart Van Assche * srp_fr_pool_put() - put an FR descriptor back in the free list 5045cfb1782SBart Van Assche * @pool: Pool the descriptor was allocated from. 5055cfb1782SBart Van Assche * @desc: Pointer to an array of fast registration descriptor pointers. 5065cfb1782SBart Van Assche * @n: Number of descriptors to put back. 5075cfb1782SBart Van Assche * 5085cfb1782SBart Van Assche * Note: The caller must already have queued an invalidation request for 5095cfb1782SBart Van Assche * desc->mr->rkey before calling this function. 5105cfb1782SBart Van Assche */ 5115cfb1782SBart Van Assche static void srp_fr_pool_put(struct srp_fr_pool *pool, struct srp_fr_desc **desc, 5125cfb1782SBart Van Assche int n) 5135cfb1782SBart Van Assche { 5145cfb1782SBart Van Assche unsigned long flags; 5155cfb1782SBart Van Assche int i; 5165cfb1782SBart Van Assche 5175cfb1782SBart Van Assche spin_lock_irqsave(&pool->lock, flags); 5185cfb1782SBart Van Assche for (i = 0; i < n; i++) 5195cfb1782SBart Van Assche list_add(&desc[i]->entry, &pool->free_list); 5205cfb1782SBart Van Assche spin_unlock_irqrestore(&pool->lock, flags); 5215cfb1782SBart Van Assche } 5225cfb1782SBart Van Assche 5235cfb1782SBart Van Assche static struct srp_fr_pool *srp_alloc_fr_pool(struct srp_target_port *target) 5245cfb1782SBart Van Assche { 5255cfb1782SBart Van Assche struct srp_device *dev = target->srp_host->srp_dev; 5265cfb1782SBart Van Assche 527fa9863f8SBart Van Assche return srp_create_fr_pool(dev->dev, dev->pd, target->mr_pool_size, 5285cfb1782SBart Van Assche dev->max_pages_per_mr); 5295cfb1782SBart Van Assche } 5305cfb1782SBart Van Assche 5317dad6b2eSBart Van Assche /** 5327dad6b2eSBart Van Assche * srp_destroy_qp() - destroy an RDMA queue pair 5339566b054SBart Van Assche * @ch: SRP RDMA channel. 5347dad6b2eSBart Van Assche * 535561392d4SSteve Wise * Drain the qp before destroying it. This avoids that the receive 536561392d4SSteve Wise * completion handler can access the queue pair while it is 5377dad6b2eSBart Van Assche * being destroyed. 5387dad6b2eSBart Van Assche */ 5399566b054SBart Van Assche static void srp_destroy_qp(struct srp_rdma_ch *ch) 5407dad6b2eSBart Van Assche { 5419294000dSBart Van Assche spin_lock_irq(&ch->lock); 5429294000dSBart Van Assche ib_process_cq_direct(ch->send_cq, -1); 5439294000dSBart Van Assche spin_unlock_irq(&ch->lock); 5449294000dSBart Van Assche 5459566b054SBart Van Assche ib_drain_qp(ch->qp); 5469566b054SBart Van Assche ib_destroy_qp(ch->qp); 5477dad6b2eSBart Van Assche } 5487dad6b2eSBart Van Assche 549509c07bcSBart Van Assche static int srp_create_ch_ib(struct srp_rdma_ch *ch) 550aef9ec39SRoland Dreier { 551509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 55262154b2eSBart Van Assche struct srp_device *dev = target->srp_host->srp_dev; 553aef9ec39SRoland Dreier struct ib_qp_init_attr *init_attr; 55473aa89edSIshai Rabinovitz struct ib_cq *recv_cq, *send_cq; 55573aa89edSIshai Rabinovitz struct ib_qp *qp; 556d1b4289eSBart Van Assche struct ib_fmr_pool *fmr_pool = NULL; 5575cfb1782SBart Van Assche struct srp_fr_pool *fr_pool = NULL; 558509c5f33SBart Van Assche const int m = 1 + dev->use_fast_reg * target->mr_per_cmd * 2; 559aef9ec39SRoland Dreier int ret; 560aef9ec39SRoland Dreier 561aef9ec39SRoland Dreier init_attr = kzalloc(sizeof *init_attr, GFP_KERNEL); 562aef9ec39SRoland Dreier if (!init_attr) 563aef9ec39SRoland Dreier return -ENOMEM; 564aef9ec39SRoland Dreier 565561392d4SSteve Wise /* queue_size + 1 for ib_drain_rq() */ 5661dc7b1f1SChristoph Hellwig recv_cq = ib_alloc_cq(dev->dev, ch, target->queue_size + 1, 5671dc7b1f1SChristoph Hellwig ch->comp_vector, IB_POLL_SOFTIRQ); 56873aa89edSIshai Rabinovitz if (IS_ERR(recv_cq)) { 56973aa89edSIshai Rabinovitz ret = PTR_ERR(recv_cq); 570da9d2f07SRoland Dreier goto err; 571aef9ec39SRoland Dreier } 572aef9ec39SRoland Dreier 5731dc7b1f1SChristoph Hellwig send_cq = ib_alloc_cq(dev->dev, ch, m * target->queue_size, 5741dc7b1f1SChristoph Hellwig ch->comp_vector, IB_POLL_DIRECT); 57573aa89edSIshai Rabinovitz if (IS_ERR(send_cq)) { 57673aa89edSIshai Rabinovitz ret = PTR_ERR(send_cq); 577da9d2f07SRoland Dreier goto err_recv_cq; 5789c03dc9fSBart Van Assche } 5799c03dc9fSBart Van Assche 580aef9ec39SRoland Dreier init_attr->event_handler = srp_qp_event; 5815cfb1782SBart Van Assche init_attr->cap.max_send_wr = m * target->queue_size; 5827dad6b2eSBart Van Assche init_attr->cap.max_recv_wr = target->queue_size + 1; 583aef9ec39SRoland Dreier init_attr->cap.max_recv_sge = 1; 584882981f4SBart Van Assche init_attr->cap.max_send_sge = SRP_MAX_SGE; 5855cfb1782SBart Van Assche init_attr->sq_sig_type = IB_SIGNAL_REQ_WR; 586aef9ec39SRoland Dreier init_attr->qp_type = IB_QPT_RC; 58773aa89edSIshai Rabinovitz init_attr->send_cq = send_cq; 58873aa89edSIshai Rabinovitz init_attr->recv_cq = recv_cq; 589aef9ec39SRoland Dreier 59019f31343SBart Van Assche if (target->using_rdma_cm) { 59119f31343SBart Van Assche ret = rdma_create_qp(ch->rdma_cm.cm_id, dev->pd, init_attr); 59219f31343SBart Van Assche qp = ch->rdma_cm.cm_id->qp; 59319f31343SBart Van Assche } else { 59462154b2eSBart Van Assche qp = ib_create_qp(dev->pd, init_attr); 59519f31343SBart Van Assche if (!IS_ERR(qp)) { 59619f31343SBart Van Assche ret = srp_init_ib_qp(target, qp); 59719f31343SBart Van Assche if (ret) 59819f31343SBart Van Assche ib_destroy_qp(qp); 59919f31343SBart Van Assche } else { 60073aa89edSIshai Rabinovitz ret = PTR_ERR(qp); 60119f31343SBart Van Assche } 60219f31343SBart Van Assche } 60319f31343SBart Van Assche if (ret) { 60419f31343SBart Van Assche pr_err("QP creation failed for dev %s: %d\n", 60519f31343SBart Van Assche dev_name(&dev->dev->dev), ret); 606da9d2f07SRoland Dreier goto err_send_cq; 607aef9ec39SRoland Dreier } 608aef9ec39SRoland Dreier 609002f1567SBart Van Assche if (dev->use_fast_reg) { 6105cfb1782SBart Van Assche fr_pool = srp_alloc_fr_pool(target); 6115cfb1782SBart Van Assche if (IS_ERR(fr_pool)) { 6125cfb1782SBart Van Assche ret = PTR_ERR(fr_pool); 6135cfb1782SBart Van Assche shost_printk(KERN_WARNING, target->scsi_host, PFX 6145cfb1782SBart Van Assche "FR pool allocation failed (%d)\n", ret); 6155cfb1782SBart Van Assche goto err_qp; 6165cfb1782SBart Van Assche } 617002f1567SBart Van Assche } else if (dev->use_fmr) { 618d1b4289eSBart Van Assche fmr_pool = srp_alloc_fmr_pool(target); 619d1b4289eSBart Van Assche if (IS_ERR(fmr_pool)) { 620d1b4289eSBart Van Assche ret = PTR_ERR(fmr_pool); 621d1b4289eSBart Van Assche shost_printk(KERN_WARNING, target->scsi_host, PFX 622d1b4289eSBart Van Assche "FMR pool allocation failed (%d)\n", ret); 623d1b4289eSBart Van Assche goto err_qp; 624d1b4289eSBart Van Assche } 625d1b4289eSBart Van Assche } 626d1b4289eSBart Van Assche 627509c07bcSBart Van Assche if (ch->qp) 6289566b054SBart Van Assche srp_destroy_qp(ch); 629509c07bcSBart Van Assche if (ch->recv_cq) 6301dc7b1f1SChristoph Hellwig ib_free_cq(ch->recv_cq); 631509c07bcSBart Van Assche if (ch->send_cq) 6321dc7b1f1SChristoph Hellwig ib_free_cq(ch->send_cq); 63373aa89edSIshai Rabinovitz 634509c07bcSBart Van Assche ch->qp = qp; 635509c07bcSBart Van Assche ch->recv_cq = recv_cq; 636509c07bcSBart Van Assche ch->send_cq = send_cq; 63773aa89edSIshai Rabinovitz 6387fbc67dfSSagi Grimberg if (dev->use_fast_reg) { 6397fbc67dfSSagi Grimberg if (ch->fr_pool) 6407fbc67dfSSagi Grimberg srp_destroy_fr_pool(ch->fr_pool); 6417fbc67dfSSagi Grimberg ch->fr_pool = fr_pool; 6427fbc67dfSSagi Grimberg } else if (dev->use_fmr) { 6437fbc67dfSSagi Grimberg if (ch->fmr_pool) 6447fbc67dfSSagi Grimberg ib_destroy_fmr_pool(ch->fmr_pool); 6457fbc67dfSSagi Grimberg ch->fmr_pool = fmr_pool; 6467fbc67dfSSagi Grimberg } 6477fbc67dfSSagi Grimberg 648da9d2f07SRoland Dreier kfree(init_attr); 649da9d2f07SRoland Dreier return 0; 650da9d2f07SRoland Dreier 651da9d2f07SRoland Dreier err_qp: 65219f31343SBart Van Assche if (target->using_rdma_cm) 65319f31343SBart Van Assche rdma_destroy_qp(ch->rdma_cm.cm_id); 65419f31343SBart Van Assche else 65595c2ef50SIsrael Rukshin ib_destroy_qp(qp); 656da9d2f07SRoland Dreier 657da9d2f07SRoland Dreier err_send_cq: 6581dc7b1f1SChristoph Hellwig ib_free_cq(send_cq); 659da9d2f07SRoland Dreier 660da9d2f07SRoland Dreier err_recv_cq: 6611dc7b1f1SChristoph Hellwig ib_free_cq(recv_cq); 662da9d2f07SRoland Dreier 663da9d2f07SRoland Dreier err: 664aef9ec39SRoland Dreier kfree(init_attr); 665aef9ec39SRoland Dreier return ret; 666aef9ec39SRoland Dreier } 667aef9ec39SRoland Dreier 6684d73f95fSBart Van Assche /* 6694d73f95fSBart Van Assche * Note: this function may be called without srp_alloc_iu_bufs() having been 670509c07bcSBart Van Assche * invoked. Hence the ch->[rt]x_ring checks. 6714d73f95fSBart Van Assche */ 672509c07bcSBart Van Assche static void srp_free_ch_ib(struct srp_target_port *target, 673509c07bcSBart Van Assche struct srp_rdma_ch *ch) 674aef9ec39SRoland Dreier { 6755cfb1782SBart Van Assche struct srp_device *dev = target->srp_host->srp_dev; 676aef9ec39SRoland Dreier int i; 677aef9ec39SRoland Dreier 678d92c0da7SBart Van Assche if (!ch->target) 679d92c0da7SBart Van Assche return; 680d92c0da7SBart Van Assche 68119f31343SBart Van Assche if (target->using_rdma_cm) { 68219f31343SBart Van Assche if (ch->rdma_cm.cm_id) { 68319f31343SBart Van Assche rdma_destroy_id(ch->rdma_cm.cm_id); 68419f31343SBart Van Assche ch->rdma_cm.cm_id = NULL; 68519f31343SBart Van Assche } 68619f31343SBart Van Assche } else { 68719f31343SBart Van Assche if (ch->ib_cm.cm_id) { 68819f31343SBart Van Assche ib_destroy_cm_id(ch->ib_cm.cm_id); 68919f31343SBart Van Assche ch->ib_cm.cm_id = NULL; 69019f31343SBart Van Assche } 691394c595eSBart Van Assche } 692394c595eSBart Van Assche 693d92c0da7SBart Van Assche /* If srp_new_cm_id() succeeded but srp_create_ch_ib() not, return. */ 694d92c0da7SBart Van Assche if (!ch->qp) 695d92c0da7SBart Van Assche return; 696d92c0da7SBart Van Assche 6975cfb1782SBart Van Assche if (dev->use_fast_reg) { 698509c07bcSBart Van Assche if (ch->fr_pool) 699509c07bcSBart Van Assche srp_destroy_fr_pool(ch->fr_pool); 700002f1567SBart Van Assche } else if (dev->use_fmr) { 701509c07bcSBart Van Assche if (ch->fmr_pool) 702509c07bcSBart Van Assche ib_destroy_fmr_pool(ch->fmr_pool); 7035cfb1782SBart Van Assche } 7041dc7b1f1SChristoph Hellwig 7059566b054SBart Van Assche srp_destroy_qp(ch); 7061dc7b1f1SChristoph Hellwig ib_free_cq(ch->send_cq); 7071dc7b1f1SChristoph Hellwig ib_free_cq(ch->recv_cq); 708aef9ec39SRoland Dreier 709d92c0da7SBart Van Assche /* 710d92c0da7SBart Van Assche * Avoid that the SCSI error handler tries to use this channel after 711d92c0da7SBart Van Assche * it has been freed. The SCSI error handler can namely continue 712d92c0da7SBart Van Assche * trying to perform recovery actions after scsi_remove_host() 713d92c0da7SBart Van Assche * returned. 714d92c0da7SBart Van Assche */ 715d92c0da7SBart Van Assche ch->target = NULL; 716d92c0da7SBart Van Assche 717509c07bcSBart Van Assche ch->qp = NULL; 718509c07bcSBart Van Assche ch->send_cq = ch->recv_cq = NULL; 71973aa89edSIshai Rabinovitz 720509c07bcSBart Van Assche if (ch->rx_ring) { 7214d73f95fSBart Van Assche for (i = 0; i < target->queue_size; ++i) 722509c07bcSBart Van Assche srp_free_iu(target->srp_host, ch->rx_ring[i]); 723509c07bcSBart Van Assche kfree(ch->rx_ring); 724509c07bcSBart Van Assche ch->rx_ring = NULL; 7254d73f95fSBart Van Assche } 726509c07bcSBart Van Assche if (ch->tx_ring) { 7274d73f95fSBart Van Assche for (i = 0; i < target->queue_size; ++i) 728509c07bcSBart Van Assche srp_free_iu(target->srp_host, ch->tx_ring[i]); 729509c07bcSBart Van Assche kfree(ch->tx_ring); 730509c07bcSBart Van Assche ch->tx_ring = NULL; 7314d73f95fSBart Van Assche } 732aef9ec39SRoland Dreier } 733aef9ec39SRoland Dreier 734aef9ec39SRoland Dreier static void srp_path_rec_completion(int status, 735c2f8fc4eSDasaratharaman Chandramouli struct sa_path_rec *pathrec, 736509c07bcSBart Van Assche void *ch_ptr) 737aef9ec39SRoland Dreier { 738509c07bcSBart Van Assche struct srp_rdma_ch *ch = ch_ptr; 739509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 740aef9ec39SRoland Dreier 741509c07bcSBart Van Assche ch->status = status; 742aef9ec39SRoland Dreier if (status) 7437aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 7447aa54bd7SDavid Dillow PFX "Got failed path rec status %d\n", status); 745aef9ec39SRoland Dreier else 74619f31343SBart Van Assche ch->ib_cm.path = *pathrec; 747509c07bcSBart Van Assche complete(&ch->done); 748aef9ec39SRoland Dreier } 749aef9ec39SRoland Dreier 75019f31343SBart Van Assche static int srp_ib_lookup_path(struct srp_rdma_ch *ch) 751aef9ec39SRoland Dreier { 752509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 753c74ff750SBart Van Assche int ret; 754a702adceSBart Van Assche 75519f31343SBart Van Assche ch->ib_cm.path.numb_path = 1; 756aef9ec39SRoland Dreier 757509c07bcSBart Van Assche init_completion(&ch->done); 758aef9ec39SRoland Dreier 75919f31343SBart Van Assche ch->ib_cm.path_query_id = ib_sa_path_rec_get(&srp_sa_client, 76005321937SGreg Kroah-Hartman target->srp_host->srp_dev->dev, 761aef9ec39SRoland Dreier target->srp_host->port, 76219f31343SBart Van Assche &ch->ib_cm.path, 763247e020eSSean Hefty IB_SA_PATH_REC_SERVICE_ID | 764aef9ec39SRoland Dreier IB_SA_PATH_REC_DGID | 765aef9ec39SRoland Dreier IB_SA_PATH_REC_SGID | 766aef9ec39SRoland Dreier IB_SA_PATH_REC_NUMB_PATH | 767aef9ec39SRoland Dreier IB_SA_PATH_REC_PKEY, 768aef9ec39SRoland Dreier SRP_PATH_REC_TIMEOUT_MS, 769aef9ec39SRoland Dreier GFP_KERNEL, 770aef9ec39SRoland Dreier srp_path_rec_completion, 77119f31343SBart Van Assche ch, &ch->ib_cm.path_query); 772c74ff750SBart Van Assche if (ch->ib_cm.path_query_id < 0) 773c74ff750SBart Van Assche return ch->ib_cm.path_query_id; 774aef9ec39SRoland Dreier 775509c07bcSBart Van Assche ret = wait_for_completion_interruptible(&ch->done); 776a702adceSBart Van Assche if (ret < 0) 777c74ff750SBart Van Assche return ret; 778aef9ec39SRoland Dreier 779c74ff750SBart Van Assche if (ch->status < 0) 7807aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 78185769c6fSBart Van Assche PFX "Path record query failed: sgid %pI6, dgid %pI6, pkey %#04x, service_id %#16llx\n", 78219f31343SBart Van Assche ch->ib_cm.path.sgid.raw, ch->ib_cm.path.dgid.raw, 78319f31343SBart Van Assche be16_to_cpu(target->ib_cm.pkey), 78419f31343SBart Van Assche be64_to_cpu(target->ib_cm.service_id)); 785aef9ec39SRoland Dreier 786c74ff750SBart Van Assche return ch->status; 787aef9ec39SRoland Dreier } 788aef9ec39SRoland Dreier 78919f31343SBart Van Assche static int srp_rdma_lookup_path(struct srp_rdma_ch *ch) 79019f31343SBart Van Assche { 79119f31343SBart Van Assche struct srp_target_port *target = ch->target; 79219f31343SBart Van Assche int ret; 79319f31343SBart Van Assche 79419f31343SBart Van Assche init_completion(&ch->done); 79519f31343SBart Van Assche 79619f31343SBart Van Assche ret = rdma_resolve_route(ch->rdma_cm.cm_id, SRP_PATH_REC_TIMEOUT_MS); 79719f31343SBart Van Assche if (ret) 79819f31343SBart Van Assche return ret; 79919f31343SBart Van Assche 80019f31343SBart Van Assche wait_for_completion_interruptible(&ch->done); 80119f31343SBart Van Assche 80219f31343SBart Van Assche if (ch->status != 0) 80319f31343SBart Van Assche shost_printk(KERN_WARNING, target->scsi_host, 80419f31343SBart Van Assche PFX "Path resolution failed\n"); 80519f31343SBart Van Assche 80619f31343SBart Van Assche return ch->status; 80719f31343SBart Van Assche } 80819f31343SBart Van Assche 80919f31343SBart Van Assche static int srp_lookup_path(struct srp_rdma_ch *ch) 81019f31343SBart Van Assche { 81119f31343SBart Van Assche struct srp_target_port *target = ch->target; 81219f31343SBart Van Assche 81319f31343SBart Van Assche return target->using_rdma_cm ? srp_rdma_lookup_path(ch) : 81419f31343SBart Van Assche srp_ib_lookup_path(ch); 81519f31343SBart Van Assche } 81619f31343SBart Van Assche 8174c532d6cSBart Van Assche static u8 srp_get_subnet_timeout(struct srp_host *host) 8184c532d6cSBart Van Assche { 8194c532d6cSBart Van Assche struct ib_port_attr attr; 8204c532d6cSBart Van Assche int ret; 8214c532d6cSBart Van Assche u8 subnet_timeout = 18; 8224c532d6cSBart Van Assche 8234c532d6cSBart Van Assche ret = ib_query_port(host->srp_dev->dev, host->port, &attr); 8244c532d6cSBart Van Assche if (ret == 0) 8254c532d6cSBart Van Assche subnet_timeout = attr.subnet_timeout; 8264c532d6cSBart Van Assche 8274c532d6cSBart Van Assche if (unlikely(subnet_timeout < 15)) 8284c532d6cSBart Van Assche pr_warn("%s: subnet timeout %d may cause SRP login to fail.\n", 8294c532d6cSBart Van Assche dev_name(&host->srp_dev->dev->dev), subnet_timeout); 8304c532d6cSBart Van Assche 8314c532d6cSBart Van Assche return subnet_timeout; 8324c532d6cSBart Van Assche } 8334c532d6cSBart Van Assche 834513d5647SBart Van Assche static int srp_send_req(struct srp_rdma_ch *ch, uint32_t max_iu_len, 835513d5647SBart Van Assche bool multich) 836aef9ec39SRoland Dreier { 837509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 838aef9ec39SRoland Dreier struct { 83919f31343SBart Van Assche struct rdma_conn_param rdma_param; 84019f31343SBart Van Assche struct srp_login_req_rdma rdma_req; 84119f31343SBart Van Assche struct ib_cm_req_param ib_param; 84219f31343SBart Van Assche struct srp_login_req ib_req; 843aef9ec39SRoland Dreier } *req = NULL; 84448900a28SBart Van Assche char *ipi, *tpi; 845aef9ec39SRoland Dreier int status; 846aef9ec39SRoland Dreier 847aef9ec39SRoland Dreier req = kzalloc(sizeof *req, GFP_KERNEL); 848aef9ec39SRoland Dreier if (!req) 849aef9ec39SRoland Dreier return -ENOMEM; 850aef9ec39SRoland Dreier 85119f31343SBart Van Assche req->ib_param.flow_control = 1; 85219f31343SBart Van Assche req->ib_param.retry_count = target->tl_retry_count; 853aef9ec39SRoland Dreier 854aef9ec39SRoland Dreier /* 855aef9ec39SRoland Dreier * Pick some arbitrary defaults here; we could make these 856aef9ec39SRoland Dreier * module parameters if anyone cared about setting them. 857aef9ec39SRoland Dreier */ 85819f31343SBart Van Assche req->ib_param.responder_resources = 4; 85919f31343SBart Van Assche req->ib_param.rnr_retry_count = 7; 86019f31343SBart Van Assche req->ib_param.max_cm_retries = 15; 861aef9ec39SRoland Dreier 86219f31343SBart Van Assche req->ib_req.opcode = SRP_LOGIN_REQ; 86319f31343SBart Van Assche req->ib_req.tag = 0; 864513d5647SBart Van Assche req->ib_req.req_it_iu_len = cpu_to_be32(max_iu_len); 86519f31343SBart Van Assche req->ib_req.req_buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT | 866aef9ec39SRoland Dreier SRP_BUF_FORMAT_INDIRECT); 86719f31343SBart Van Assche req->ib_req.req_flags = (multich ? SRP_MULTICHAN_MULTI : 868d92c0da7SBart Van Assche SRP_MULTICHAN_SINGLE); 869882981f4SBart Van Assche if (srp_use_imm_data) { 870882981f4SBart Van Assche req->ib_req.req_flags |= SRP_IMMED_REQUESTED; 871882981f4SBart Van Assche req->ib_req.imm_data_offset = cpu_to_be16(SRP_IMM_DATA_OFFSET); 872882981f4SBart Van Assche } 87348900a28SBart Van Assche 87419f31343SBart Van Assche if (target->using_rdma_cm) { 87519f31343SBart Van Assche req->rdma_param.flow_control = req->ib_param.flow_control; 87619f31343SBart Van Assche req->rdma_param.responder_resources = 87719f31343SBart Van Assche req->ib_param.responder_resources; 87819f31343SBart Van Assche req->rdma_param.initiator_depth = req->ib_param.initiator_depth; 87919f31343SBart Van Assche req->rdma_param.retry_count = req->ib_param.retry_count; 88019f31343SBart Van Assche req->rdma_param.rnr_retry_count = req->ib_param.rnr_retry_count; 88119f31343SBart Van Assche req->rdma_param.private_data = &req->rdma_req; 88219f31343SBart Van Assche req->rdma_param.private_data_len = sizeof(req->rdma_req); 88319f31343SBart Van Assche 88419f31343SBart Van Assche req->rdma_req.opcode = req->ib_req.opcode; 88519f31343SBart Van Assche req->rdma_req.tag = req->ib_req.tag; 88619f31343SBart Van Assche req->rdma_req.req_it_iu_len = req->ib_req.req_it_iu_len; 88719f31343SBart Van Assche req->rdma_req.req_buf_fmt = req->ib_req.req_buf_fmt; 88819f31343SBart Van Assche req->rdma_req.req_flags = req->ib_req.req_flags; 889882981f4SBart Van Assche req->rdma_req.imm_data_offset = req->ib_req.imm_data_offset; 89019f31343SBart Van Assche 89119f31343SBart Van Assche ipi = req->rdma_req.initiator_port_id; 89219f31343SBart Van Assche tpi = req->rdma_req.target_port_id; 89319f31343SBart Van Assche } else { 89448900a28SBart Van Assche u8 subnet_timeout; 89548900a28SBart Van Assche 89648900a28SBart Van Assche subnet_timeout = srp_get_subnet_timeout(target->srp_host); 89748900a28SBart Van Assche 89819f31343SBart Van Assche req->ib_param.primary_path = &ch->ib_cm.path; 89919f31343SBart Van Assche req->ib_param.alternate_path = NULL; 90019f31343SBart Van Assche req->ib_param.service_id = target->ib_cm.service_id; 90119f31343SBart Van Assche get_random_bytes(&req->ib_param.starting_psn, 4); 90219f31343SBart Van Assche req->ib_param.starting_psn &= 0xffffff; 90319f31343SBart Van Assche req->ib_param.qp_num = ch->qp->qp_num; 90419f31343SBart Van Assche req->ib_param.qp_type = ch->qp->qp_type; 90519f31343SBart Van Assche req->ib_param.local_cm_response_timeout = subnet_timeout + 2; 90619f31343SBart Van Assche req->ib_param.remote_cm_response_timeout = subnet_timeout + 2; 90719f31343SBart Van Assche req->ib_param.private_data = &req->ib_req; 90819f31343SBart Van Assche req->ib_param.private_data_len = sizeof(req->ib_req); 90948900a28SBart Van Assche 91019f31343SBart Van Assche ipi = req->ib_req.initiator_port_id; 91119f31343SBart Van Assche tpi = req->ib_req.target_port_id; 91248900a28SBart Van Assche } 91348900a28SBart Van Assche 9140c0450dbSRamachandra K /* 9150c0450dbSRamachandra K * In the published SRP specification (draft rev. 16a), the 9160c0450dbSRamachandra K * port identifier format is 8 bytes of ID extension followed 9170c0450dbSRamachandra K * by 8 bytes of GUID. Older drafts put the two halves in the 9180c0450dbSRamachandra K * opposite order, so that the GUID comes first. 9190c0450dbSRamachandra K * 9200c0450dbSRamachandra K * Targets conforming to these obsolete drafts can be 9210c0450dbSRamachandra K * recognized by the I/O Class they report. 9220c0450dbSRamachandra K */ 9230c0450dbSRamachandra K if (target->io_class == SRP_REV10_IB_IO_CLASS) { 92448900a28SBart Van Assche memcpy(ipi, &target->sgid.global.interface_id, 8); 92548900a28SBart Van Assche memcpy(ipi + 8, &target->initiator_ext, 8); 92648900a28SBart Van Assche memcpy(tpi, &target->ioc_guid, 8); 92748900a28SBart Van Assche memcpy(tpi + 8, &target->id_ext, 8); 9280c0450dbSRamachandra K } else { 92948900a28SBart Van Assche memcpy(ipi, &target->initiator_ext, 8); 93048900a28SBart Van Assche memcpy(ipi + 8, &target->sgid.global.interface_id, 8); 93148900a28SBart Van Assche memcpy(tpi, &target->id_ext, 8); 93248900a28SBart Van Assche memcpy(tpi + 8, &target->ioc_guid, 8); 9330c0450dbSRamachandra K } 9340c0450dbSRamachandra K 935aef9ec39SRoland Dreier /* 936aef9ec39SRoland Dreier * Topspin/Cisco SRP targets will reject our login unless we 93701cb9bcbSIshai Rabinovitz * zero out the first 8 bytes of our initiator port ID and set 93801cb9bcbSIshai Rabinovitz * the second 8 bytes to the local node GUID. 939aef9ec39SRoland Dreier */ 9405d7cbfd6SRoland Dreier if (srp_target_is_topspin(target)) { 9417aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, target->scsi_host, 9427aa54bd7SDavid Dillow PFX "Topspin/Cisco initiator port ID workaround " 943aef9ec39SRoland Dreier "activated for target GUID %016llx\n", 94445c37cadSBart Van Assche be64_to_cpu(target->ioc_guid)); 94548900a28SBart Van Assche memset(ipi, 0, 8); 94648900a28SBart Van Assche memcpy(ipi + 8, &target->srp_host->srp_dev->dev->node_guid, 8); 947aef9ec39SRoland Dreier } 948aef9ec39SRoland Dreier 94919f31343SBart Van Assche if (target->using_rdma_cm) 95019f31343SBart Van Assche status = rdma_connect(ch->rdma_cm.cm_id, &req->rdma_param); 95119f31343SBart Van Assche else 95219f31343SBart Van Assche status = ib_send_cm_req(ch->ib_cm.cm_id, &req->ib_param); 953aef9ec39SRoland Dreier 954aef9ec39SRoland Dreier kfree(req); 955aef9ec39SRoland Dreier 956aef9ec39SRoland Dreier return status; 957aef9ec39SRoland Dreier } 958aef9ec39SRoland Dreier 959ef6c49d8SBart Van Assche static bool srp_queue_remove_work(struct srp_target_port *target) 960ef6c49d8SBart Van Assche { 961ef6c49d8SBart Van Assche bool changed = false; 962ef6c49d8SBart Van Assche 963ef6c49d8SBart Van Assche spin_lock_irq(&target->lock); 964ef6c49d8SBart Van Assche if (target->state != SRP_TARGET_REMOVED) { 965ef6c49d8SBart Van Assche target->state = SRP_TARGET_REMOVED; 966ef6c49d8SBart Van Assche changed = true; 967ef6c49d8SBart Van Assche } 968ef6c49d8SBart Van Assche spin_unlock_irq(&target->lock); 969ef6c49d8SBart Van Assche 970ef6c49d8SBart Van Assche if (changed) 971bcc05910SBart Van Assche queue_work(srp_remove_wq, &target->remove_work); 972ef6c49d8SBart Van Assche 973ef6c49d8SBart Van Assche return changed; 974ef6c49d8SBart Van Assche } 975ef6c49d8SBart Van Assche 976aef9ec39SRoland Dreier static void srp_disconnect_target(struct srp_target_port *target) 977aef9ec39SRoland Dreier { 978d92c0da7SBart Van Assche struct srp_rdma_ch *ch; 97919f31343SBart Van Assche int i, ret; 980509c07bcSBart Van Assche 981aef9ec39SRoland Dreier /* XXX should send SRP_I_LOGOUT request */ 982aef9ec39SRoland Dreier 983d92c0da7SBart Van Assche for (i = 0; i < target->ch_count; i++) { 984d92c0da7SBart Van Assche ch = &target->ch[i]; 985c014c8cdSBart Van Assche ch->connected = false; 98619f31343SBart Van Assche ret = 0; 98719f31343SBart Van Assche if (target->using_rdma_cm) { 98819f31343SBart Van Assche if (ch->rdma_cm.cm_id) 98919f31343SBart Van Assche rdma_disconnect(ch->rdma_cm.cm_id); 99019f31343SBart Van Assche } else { 99119f31343SBart Van Assche if (ch->ib_cm.cm_id) 99219f31343SBart Van Assche ret = ib_send_cm_dreq(ch->ib_cm.cm_id, 99319f31343SBart Van Assche NULL, 0); 99419f31343SBart Van Assche } 99519f31343SBart Van Assche if (ret < 0) { 9967aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, target->scsi_host, 9977aa54bd7SDavid Dillow PFX "Sending CM DREQ failed\n"); 998aef9ec39SRoland Dreier } 999294c875aSBart Van Assche } 1000294c875aSBart Van Assche } 1001aef9ec39SRoland Dreier 1002509c07bcSBart Van Assche static void srp_free_req_data(struct srp_target_port *target, 1003509c07bcSBart Van Assche struct srp_rdma_ch *ch) 10048f26c9ffSDavid Dillow { 10055cfb1782SBart Van Assche struct srp_device *dev = target->srp_host->srp_dev; 10065cfb1782SBart Van Assche struct ib_device *ibdev = dev->dev; 10078f26c9ffSDavid Dillow struct srp_request *req; 10088f26c9ffSDavid Dillow int i; 10098f26c9ffSDavid Dillow 101047513cf4SBart Van Assche if (!ch->req_ring) 10114d73f95fSBart Van Assche return; 10124d73f95fSBart Van Assche 10134d73f95fSBart Van Assche for (i = 0; i < target->req_ring_size; ++i) { 1014509c07bcSBart Van Assche req = &ch->req_ring[i]; 10159a21be53SSagi Grimberg if (dev->use_fast_reg) { 10165cfb1782SBart Van Assche kfree(req->fr_list); 10179a21be53SSagi Grimberg } else { 10188f26c9ffSDavid Dillow kfree(req->fmr_list); 10198f26c9ffSDavid Dillow kfree(req->map_page); 10209a21be53SSagi Grimberg } 1021c07d424dSDavid Dillow if (req->indirect_dma_addr) { 1022c07d424dSDavid Dillow ib_dma_unmap_single(ibdev, req->indirect_dma_addr, 1023c07d424dSDavid Dillow target->indirect_size, 1024c07d424dSDavid Dillow DMA_TO_DEVICE); 1025c07d424dSDavid Dillow } 1026c07d424dSDavid Dillow kfree(req->indirect_desc); 10278f26c9ffSDavid Dillow } 10284d73f95fSBart Van Assche 1029509c07bcSBart Van Assche kfree(ch->req_ring); 1030509c07bcSBart Van Assche ch->req_ring = NULL; 10318f26c9ffSDavid Dillow } 10328f26c9ffSDavid Dillow 1033509c07bcSBart Van Assche static int srp_alloc_req_data(struct srp_rdma_ch *ch) 1034b81d00bdSBart Van Assche { 1035509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 1036b81d00bdSBart Van Assche struct srp_device *srp_dev = target->srp_host->srp_dev; 1037b81d00bdSBart Van Assche struct ib_device *ibdev = srp_dev->dev; 1038b81d00bdSBart Van Assche struct srp_request *req; 10395cfb1782SBart Van Assche void *mr_list; 1040b81d00bdSBart Van Assche dma_addr_t dma_addr; 1041b81d00bdSBart Van Assche int i, ret = -ENOMEM; 1042b81d00bdSBart Van Assche 1043509c07bcSBart Van Assche ch->req_ring = kcalloc(target->req_ring_size, sizeof(*ch->req_ring), 1044509c07bcSBart Van Assche GFP_KERNEL); 1045509c07bcSBart Van Assche if (!ch->req_ring) 10464d73f95fSBart Van Assche goto out; 10474d73f95fSBart Van Assche 10484d73f95fSBart Van Assche for (i = 0; i < target->req_ring_size; ++i) { 1049509c07bcSBart Van Assche req = &ch->req_ring[i]; 10506da2ec56SKees Cook mr_list = kmalloc_array(target->mr_per_cmd, sizeof(void *), 1051b81d00bdSBart Van Assche GFP_KERNEL); 10525cfb1782SBart Van Assche if (!mr_list) 10535cfb1782SBart Van Assche goto out; 10549a21be53SSagi Grimberg if (srp_dev->use_fast_reg) { 10555cfb1782SBart Van Assche req->fr_list = mr_list; 10569a21be53SSagi Grimberg } else { 10575cfb1782SBart Van Assche req->fmr_list = mr_list; 10586da2ec56SKees Cook req->map_page = kmalloc_array(srp_dev->max_pages_per_mr, 10596da2ec56SKees Cook sizeof(void *), 10606da2ec56SKees Cook GFP_KERNEL); 10615cfb1782SBart Van Assche if (!req->map_page) 10625cfb1782SBart Van Assche goto out; 10639a21be53SSagi Grimberg } 1064b81d00bdSBart Van Assche req->indirect_desc = kmalloc(target->indirect_size, GFP_KERNEL); 10655cfb1782SBart Van Assche if (!req->indirect_desc) 1066b81d00bdSBart Van Assche goto out; 1067b81d00bdSBart Van Assche 1068b81d00bdSBart Van Assche dma_addr = ib_dma_map_single(ibdev, req->indirect_desc, 1069b81d00bdSBart Van Assche target->indirect_size, 1070b81d00bdSBart Van Assche DMA_TO_DEVICE); 1071b81d00bdSBart Van Assche if (ib_dma_mapping_error(ibdev, dma_addr)) 1072b81d00bdSBart Van Assche goto out; 1073b81d00bdSBart Van Assche 1074b81d00bdSBart Van Assche req->indirect_dma_addr = dma_addr; 1075b81d00bdSBart Van Assche } 1076b81d00bdSBart Van Assche ret = 0; 1077b81d00bdSBart Van Assche 1078b81d00bdSBart Van Assche out: 1079b81d00bdSBart Van Assche return ret; 1080b81d00bdSBart Van Assche } 1081b81d00bdSBart Van Assche 1082683b159aSBart Van Assche /** 1083683b159aSBart Van Assche * srp_del_scsi_host_attr() - Remove attributes defined in the host template. 1084683b159aSBart Van Assche * @shost: SCSI host whose attributes to remove from sysfs. 1085683b159aSBart Van Assche * 1086683b159aSBart Van Assche * Note: Any attributes defined in the host template and that did not exist 1087683b159aSBart Van Assche * before invocation of this function will be ignored. 1088683b159aSBart Van Assche */ 1089683b159aSBart Van Assche static void srp_del_scsi_host_attr(struct Scsi_Host *shost) 1090683b159aSBart Van Assche { 1091683b159aSBart Van Assche struct device_attribute **attr; 1092683b159aSBart Van Assche 1093683b159aSBart Van Assche for (attr = shost->hostt->shost_attrs; attr && *attr; ++attr) 1094683b159aSBart Van Assche device_remove_file(&shost->shost_dev, *attr); 1095683b159aSBart Van Assche } 1096683b159aSBart Van Assche 1097ee12d6a8SBart Van Assche static void srp_remove_target(struct srp_target_port *target) 1098ee12d6a8SBart Van Assche { 1099d92c0da7SBart Van Assche struct srp_rdma_ch *ch; 1100d92c0da7SBart Van Assche int i; 1101509c07bcSBart Van Assche 1102ef6c49d8SBart Van Assche WARN_ON_ONCE(target->state != SRP_TARGET_REMOVED); 1103ef6c49d8SBart Van Assche 1104ee12d6a8SBart Van Assche srp_del_scsi_host_attr(target->scsi_host); 11059dd69a60SBart Van Assche srp_rport_get(target->rport); 1106ee12d6a8SBart Van Assche srp_remove_host(target->scsi_host); 1107ee12d6a8SBart Van Assche scsi_remove_host(target->scsi_host); 110893079162SBart Van Assche srp_stop_rport_timers(target->rport); 1109ef6c49d8SBart Van Assche srp_disconnect_target(target); 111019f31343SBart Van Assche kobj_ns_drop(KOBJ_NS_TYPE_NET, target->net); 1111d92c0da7SBart Van Assche for (i = 0; i < target->ch_count; i++) { 1112d92c0da7SBart Van Assche ch = &target->ch[i]; 1113509c07bcSBart Van Assche srp_free_ch_ib(target, ch); 1114d92c0da7SBart Van Assche } 1115c1120f89SBart Van Assche cancel_work_sync(&target->tl_err_work); 11169dd69a60SBart Van Assche srp_rport_put(target->rport); 1117d92c0da7SBart Van Assche for (i = 0; i < target->ch_count; i++) { 1118d92c0da7SBart Van Assche ch = &target->ch[i]; 1119509c07bcSBart Van Assche srp_free_req_data(target, ch); 1120d92c0da7SBart Van Assche } 1121d92c0da7SBart Van Assche kfree(target->ch); 1122d92c0da7SBart Van Assche target->ch = NULL; 112365d7dd2fSVu Pham 112465d7dd2fSVu Pham spin_lock(&target->srp_host->target_lock); 112565d7dd2fSVu Pham list_del(&target->list); 112665d7dd2fSVu Pham spin_unlock(&target->srp_host->target_lock); 112765d7dd2fSVu Pham 1128ee12d6a8SBart Van Assche scsi_host_put(target->scsi_host); 1129ee12d6a8SBart Van Assche } 1130ee12d6a8SBart Van Assche 1131c4028958SDavid Howells static void srp_remove_work(struct work_struct *work) 1132aef9ec39SRoland Dreier { 1133c4028958SDavid Howells struct srp_target_port *target = 1134ef6c49d8SBart Van Assche container_of(work, struct srp_target_port, remove_work); 1135aef9ec39SRoland Dreier 1136ef6c49d8SBart Van Assche WARN_ON_ONCE(target->state != SRP_TARGET_REMOVED); 1137aef9ec39SRoland Dreier 113896fc248aSBart Van Assche srp_remove_target(target); 1139aef9ec39SRoland Dreier } 1140aef9ec39SRoland Dreier 1141dc1bdbd9SBart Van Assche static void srp_rport_delete(struct srp_rport *rport) 1142dc1bdbd9SBart Van Assche { 1143dc1bdbd9SBart Van Assche struct srp_target_port *target = rport->lld_data; 1144dc1bdbd9SBart Van Assche 1145dc1bdbd9SBart Van Assche srp_queue_remove_work(target); 1146dc1bdbd9SBart Van Assche } 1147dc1bdbd9SBart Van Assche 1148c014c8cdSBart Van Assche /** 1149c014c8cdSBart Van Assche * srp_connected_ch() - number of connected channels 1150c014c8cdSBart Van Assche * @target: SRP target port. 1151c014c8cdSBart Van Assche */ 1152c014c8cdSBart Van Assche static int srp_connected_ch(struct srp_target_port *target) 1153c014c8cdSBart Van Assche { 1154c014c8cdSBart Van Assche int i, c = 0; 1155c014c8cdSBart Van Assche 1156c014c8cdSBart Van Assche for (i = 0; i < target->ch_count; i++) 1157c014c8cdSBart Van Assche c += target->ch[i].connected; 1158c014c8cdSBart Van Assche 1159c014c8cdSBart Van Assche return c; 1160c014c8cdSBart Van Assche } 1161c014c8cdSBart Van Assche 1162513d5647SBart Van Assche static int srp_connect_ch(struct srp_rdma_ch *ch, uint32_t max_iu_len, 1163513d5647SBart Van Assche bool multich) 1164aef9ec39SRoland Dreier { 1165509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 1166aef9ec39SRoland Dreier int ret; 1167aef9ec39SRoland Dreier 1168c014c8cdSBart Van Assche WARN_ON_ONCE(!multich && srp_connected_ch(target) > 0); 1169294c875aSBart Van Assche 1170509c07bcSBart Van Assche ret = srp_lookup_path(ch); 1171aef9ec39SRoland Dreier if (ret) 11724d59ad29SBart Van Assche goto out; 1173aef9ec39SRoland Dreier 1174aef9ec39SRoland Dreier while (1) { 1175509c07bcSBart Van Assche init_completion(&ch->done); 1176513d5647SBart Van Assche ret = srp_send_req(ch, max_iu_len, multich); 1177aef9ec39SRoland Dreier if (ret) 11784d59ad29SBart Van Assche goto out; 1179509c07bcSBart Van Assche ret = wait_for_completion_interruptible(&ch->done); 1180a702adceSBart Van Assche if (ret < 0) 11814d59ad29SBart Van Assche goto out; 1182aef9ec39SRoland Dreier 1183aef9ec39SRoland Dreier /* 1184aef9ec39SRoland Dreier * The CM event handling code will set status to 1185aef9ec39SRoland Dreier * SRP_PORT_REDIRECT if we get a port redirect REJ 1186aef9ec39SRoland Dreier * back, or SRP_DLID_REDIRECT if we get a lid/qp 1187aef9ec39SRoland Dreier * redirect REJ back. 1188aef9ec39SRoland Dreier */ 11894d59ad29SBart Van Assche ret = ch->status; 11904d59ad29SBart Van Assche switch (ret) { 1191aef9ec39SRoland Dreier case 0: 1192c014c8cdSBart Van Assche ch->connected = true; 11934d59ad29SBart Van Assche goto out; 1194aef9ec39SRoland Dreier 1195aef9ec39SRoland Dreier case SRP_PORT_REDIRECT: 1196509c07bcSBart Van Assche ret = srp_lookup_path(ch); 1197aef9ec39SRoland Dreier if (ret) 11984d59ad29SBart Van Assche goto out; 1199aef9ec39SRoland Dreier break; 1200aef9ec39SRoland Dreier 1201aef9ec39SRoland Dreier case SRP_DLID_REDIRECT: 1202aef9ec39SRoland Dreier break; 1203aef9ec39SRoland Dreier 12049fe4bcf4SDavid Dillow case SRP_STALE_CONN: 12059fe4bcf4SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX 12069fe4bcf4SDavid Dillow "giving up on stale connection\n"); 12074d59ad29SBart Van Assche ret = -ECONNRESET; 12084d59ad29SBart Van Assche goto out; 12099fe4bcf4SDavid Dillow 1210aef9ec39SRoland Dreier default: 12114d59ad29SBart Van Assche goto out; 1212aef9ec39SRoland Dreier } 1213aef9ec39SRoland Dreier } 12144d59ad29SBart Van Assche 12154d59ad29SBart Van Assche out: 12164d59ad29SBart Van Assche return ret <= 0 ? ret : -ENODEV; 1217aef9ec39SRoland Dreier } 1218aef9ec39SRoland Dreier 12191dc7b1f1SChristoph Hellwig static void srp_inv_rkey_err_done(struct ib_cq *cq, struct ib_wc *wc) 12201dc7b1f1SChristoph Hellwig { 12211dc7b1f1SChristoph Hellwig srp_handle_qp_err(cq, wc, "INV RKEY"); 12221dc7b1f1SChristoph Hellwig } 12231dc7b1f1SChristoph Hellwig 12241dc7b1f1SChristoph Hellwig static int srp_inv_rkey(struct srp_request *req, struct srp_rdma_ch *ch, 12251dc7b1f1SChristoph Hellwig u32 rkey) 12265cfb1782SBart Van Assche { 12275cfb1782SBart Van Assche struct ib_send_wr wr = { 12285cfb1782SBart Van Assche .opcode = IB_WR_LOCAL_INV, 12295cfb1782SBart Van Assche .next = NULL, 12305cfb1782SBart Van Assche .num_sge = 0, 12315cfb1782SBart Van Assche .send_flags = 0, 12325cfb1782SBart Van Assche .ex.invalidate_rkey = rkey, 12335cfb1782SBart Van Assche }; 12345cfb1782SBart Van Assche 12351dc7b1f1SChristoph Hellwig wr.wr_cqe = &req->reg_cqe; 12361dc7b1f1SChristoph Hellwig req->reg_cqe.done = srp_inv_rkey_err_done; 123771347b0cSBart Van Assche return ib_post_send(ch->qp, &wr, NULL); 12385cfb1782SBart Van Assche } 12395cfb1782SBart Van Assche 1240d945e1dfSRoland Dreier static void srp_unmap_data(struct scsi_cmnd *scmnd, 1241509c07bcSBart Van Assche struct srp_rdma_ch *ch, 1242d945e1dfSRoland Dreier struct srp_request *req) 1243d945e1dfSRoland Dreier { 1244509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 12455cfb1782SBart Van Assche struct srp_device *dev = target->srp_host->srp_dev; 12465cfb1782SBart Van Assche struct ib_device *ibdev = dev->dev; 12475cfb1782SBart Van Assche int i, res; 12488f26c9ffSDavid Dillow 1249bb350d1dSFUJITA Tomonori if (!scsi_sglist(scmnd) || 1250d945e1dfSRoland Dreier (scmnd->sc_data_direction != DMA_TO_DEVICE && 1251d945e1dfSRoland Dreier scmnd->sc_data_direction != DMA_FROM_DEVICE)) 1252d945e1dfSRoland Dreier return; 1253d945e1dfSRoland Dreier 12545cfb1782SBart Van Assche if (dev->use_fast_reg) { 12555cfb1782SBart Van Assche struct srp_fr_desc **pfr; 12565cfb1782SBart Van Assche 12575cfb1782SBart Van Assche for (i = req->nmdesc, pfr = req->fr_list; i > 0; i--, pfr++) { 12581dc7b1f1SChristoph Hellwig res = srp_inv_rkey(req, ch, (*pfr)->mr->rkey); 12595cfb1782SBart Van Assche if (res < 0) { 12605cfb1782SBart Van Assche shost_printk(KERN_ERR, target->scsi_host, PFX 12615cfb1782SBart Van Assche "Queueing INV WR for rkey %#x failed (%d)\n", 12625cfb1782SBart Van Assche (*pfr)->mr->rkey, res); 12635cfb1782SBart Van Assche queue_work(system_long_wq, 12645cfb1782SBart Van Assche &target->tl_err_work); 12655cfb1782SBart Van Assche } 12665cfb1782SBart Van Assche } 12675cfb1782SBart Van Assche if (req->nmdesc) 1268509c07bcSBart Van Assche srp_fr_pool_put(ch->fr_pool, req->fr_list, 12695cfb1782SBart Van Assche req->nmdesc); 1270002f1567SBart Van Assche } else if (dev->use_fmr) { 12715cfb1782SBart Van Assche struct ib_pool_fmr **pfmr; 12725cfb1782SBart Van Assche 12735cfb1782SBart Van Assche for (i = req->nmdesc, pfmr = req->fmr_list; i > 0; i--, pfmr++) 12745cfb1782SBart Van Assche ib_fmr_pool_unmap(*pfmr); 12755cfb1782SBart Van Assche } 1276f5358a17SRoland Dreier 12778f26c9ffSDavid Dillow ib_dma_unmap_sg(ibdev, scsi_sglist(scmnd), scsi_sg_count(scmnd), 12788f26c9ffSDavid Dillow scmnd->sc_data_direction); 1279d945e1dfSRoland Dreier } 1280d945e1dfSRoland Dreier 128122032991SBart Van Assche /** 128222032991SBart Van Assche * srp_claim_req - Take ownership of the scmnd associated with a request. 1283509c07bcSBart Van Assche * @ch: SRP RDMA channel. 128422032991SBart Van Assche * @req: SRP request. 1285b3fe628dSBart Van Assche * @sdev: If not NULL, only take ownership for this SCSI device. 128622032991SBart Van Assche * @scmnd: If NULL, take ownership of @req->scmnd. If not NULL, only take 128722032991SBart Van Assche * ownership of @req->scmnd if it equals @scmnd. 128822032991SBart Van Assche * 128922032991SBart Van Assche * Return value: 129022032991SBart Van Assche * Either NULL or a pointer to the SCSI command the caller became owner of. 129122032991SBart Van Assche */ 1292509c07bcSBart Van Assche static struct scsi_cmnd *srp_claim_req(struct srp_rdma_ch *ch, 129322032991SBart Van Assche struct srp_request *req, 1294b3fe628dSBart Van Assche struct scsi_device *sdev, 129522032991SBart Van Assche struct scsi_cmnd *scmnd) 1296526b4caaSIshai Rabinovitz { 129794a9174cSBart Van Assche unsigned long flags; 129894a9174cSBart Van Assche 1299509c07bcSBart Van Assche spin_lock_irqsave(&ch->lock, flags); 1300b3fe628dSBart Van Assche if (req->scmnd && 1301b3fe628dSBart Van Assche (!sdev || req->scmnd->device == sdev) && 1302b3fe628dSBart Van Assche (!scmnd || req->scmnd == scmnd)) { 130322032991SBart Van Assche scmnd = req->scmnd; 130422032991SBart Van Assche req->scmnd = NULL; 130522032991SBart Van Assche } else { 130622032991SBart Van Assche scmnd = NULL; 130722032991SBart Van Assche } 1308509c07bcSBart Van Assche spin_unlock_irqrestore(&ch->lock, flags); 130922032991SBart Van Assche 131022032991SBart Van Assche return scmnd; 131122032991SBart Van Assche } 131222032991SBart Van Assche 131322032991SBart Van Assche /** 13146ec2ba02SBart Van Assche * srp_free_req() - Unmap data and adjust ch->req_lim. 1315509c07bcSBart Van Assche * @ch: SRP RDMA channel. 1316af24663bSBart Van Assche * @req: Request to be freed. 1317af24663bSBart Van Assche * @scmnd: SCSI command associated with @req. 1318af24663bSBart Van Assche * @req_lim_delta: Amount to be added to @target->req_lim. 131922032991SBart Van Assche */ 1320509c07bcSBart Van Assche static void srp_free_req(struct srp_rdma_ch *ch, struct srp_request *req, 1321509c07bcSBart Van Assche struct scsi_cmnd *scmnd, s32 req_lim_delta) 132222032991SBart Van Assche { 132322032991SBart Van Assche unsigned long flags; 132422032991SBart Van Assche 1325509c07bcSBart Van Assche srp_unmap_data(scmnd, ch, req); 132622032991SBart Van Assche 1327509c07bcSBart Van Assche spin_lock_irqsave(&ch->lock, flags); 1328509c07bcSBart Van Assche ch->req_lim += req_lim_delta; 1329509c07bcSBart Van Assche spin_unlock_irqrestore(&ch->lock, flags); 1330526b4caaSIshai Rabinovitz } 1331526b4caaSIshai Rabinovitz 1332509c07bcSBart Van Assche static void srp_finish_req(struct srp_rdma_ch *ch, struct srp_request *req, 1333509c07bcSBart Van Assche struct scsi_device *sdev, int result) 1334526b4caaSIshai Rabinovitz { 1335509c07bcSBart Van Assche struct scsi_cmnd *scmnd = srp_claim_req(ch, req, sdev, NULL); 133622032991SBart Van Assche 133722032991SBart Van Assche if (scmnd) { 1338509c07bcSBart Van Assche srp_free_req(ch, req, scmnd, 0); 1339ed9b2264SBart Van Assche scmnd->result = result; 134022032991SBart Van Assche scmnd->scsi_done(scmnd); 134122032991SBart Van Assche } 1342526b4caaSIshai Rabinovitz } 1343526b4caaSIshai Rabinovitz 1344ed9b2264SBart Van Assche static void srp_terminate_io(struct srp_rport *rport) 1345aef9ec39SRoland Dreier { 1346ed9b2264SBart Van Assche struct srp_target_port *target = rport->lld_data; 1347d92c0da7SBart Van Assche struct srp_rdma_ch *ch; 1348d92c0da7SBart Van Assche int i, j; 1349aef9ec39SRoland Dreier 1350d92c0da7SBart Van Assche for (i = 0; i < target->ch_count; i++) { 1351d92c0da7SBart Van Assche ch = &target->ch[i]; 1352509c07bcSBart Van Assche 1353d92c0da7SBart Van Assche for (j = 0; j < target->req_ring_size; ++j) { 1354d92c0da7SBart Van Assche struct srp_request *req = &ch->req_ring[j]; 1355d92c0da7SBart Van Assche 1356d92c0da7SBart Van Assche srp_finish_req(ch, req, NULL, 1357d92c0da7SBart Van Assche DID_TRANSPORT_FAILFAST << 16); 1358d92c0da7SBart Van Assche } 1359ed9b2264SBart Van Assche } 1360ed9b2264SBart Van Assche } 1361ed9b2264SBart Van Assche 1362513d5647SBart Van Assche /* Calculate maximum initiator to target information unit length. */ 1363882981f4SBart Van Assche static uint32_t srp_max_it_iu_len(int cmd_sg_cnt, bool use_imm_data) 1364513d5647SBart Van Assche { 1365513d5647SBart Van Assche uint32_t max_iu_len = sizeof(struct srp_cmd) + SRP_MAX_ADD_CDB_LEN + 1366513d5647SBart Van Assche sizeof(struct srp_indirect_buf) + 1367513d5647SBart Van Assche cmd_sg_cnt * sizeof(struct srp_direct_buf); 1368513d5647SBart Van Assche 1369882981f4SBart Van Assche if (use_imm_data) 1370882981f4SBart Van Assche max_iu_len = max(max_iu_len, SRP_IMM_DATA_OFFSET + 1371882981f4SBart Van Assche srp_max_imm_data); 1372882981f4SBart Van Assche 1373513d5647SBart Van Assche return max_iu_len; 1374513d5647SBart Van Assche } 1375513d5647SBart Van Assche 1376ed9b2264SBart Van Assche /* 1377ed9b2264SBart Van Assche * It is up to the caller to ensure that srp_rport_reconnect() calls are 1378ed9b2264SBart Van Assche * serialized and that no concurrent srp_queuecommand(), srp_abort(), 1379ed9b2264SBart Van Assche * srp_reset_device() or srp_reset_host() calls will occur while this function 1380ed9b2264SBart Van Assche * is in progress. One way to realize that is not to call this function 1381ed9b2264SBart Van Assche * directly but to call srp_reconnect_rport() instead since that last function 1382ed9b2264SBart Van Assche * serializes calls of this function via rport->mutex and also blocks 1383ed9b2264SBart Van Assche * srp_queuecommand() calls before invoking this function. 1384ed9b2264SBart Van Assche */ 1385ed9b2264SBart Van Assche static int srp_rport_reconnect(struct srp_rport *rport) 1386ed9b2264SBart Van Assche { 1387ed9b2264SBart Van Assche struct srp_target_port *target = rport->lld_data; 1388d92c0da7SBart Van Assche struct srp_rdma_ch *ch; 1389882981f4SBart Van Assche uint32_t max_iu_len = srp_max_it_iu_len(target->cmd_sg_cnt, 1390882981f4SBart Van Assche srp_use_imm_data); 1391d92c0da7SBart Van Assche int i, j, ret = 0; 1392d92c0da7SBart Van Assche bool multich = false; 139309be70a2SBart Van Assche 1394aef9ec39SRoland Dreier srp_disconnect_target(target); 139534aa654eSBart Van Assche 139634aa654eSBart Van Assche if (target->state == SRP_TARGET_SCANNING) 139734aa654eSBart Van Assche return -ENODEV; 139834aa654eSBart Van Assche 1399aef9ec39SRoland Dreier /* 1400c7c4e7ffSBart Van Assche * Now get a new local CM ID so that we avoid confusing the target in 1401c7c4e7ffSBart Van Assche * case things are really fouled up. Doing so also ensures that all CM 1402c7c4e7ffSBart Van Assche * callbacks will have finished before a new QP is allocated. 1403aef9ec39SRoland Dreier */ 1404d92c0da7SBart Van Assche for (i = 0; i < target->ch_count; i++) { 1405d92c0da7SBart Van Assche ch = &target->ch[i]; 1406d92c0da7SBart Van Assche ret += srp_new_cm_id(ch); 1407d92c0da7SBart Van Assche } 1408d92c0da7SBart Van Assche for (i = 0; i < target->ch_count; i++) { 1409d92c0da7SBart Van Assche ch = &target->ch[i]; 1410d92c0da7SBart Van Assche for (j = 0; j < target->req_ring_size; ++j) { 1411d92c0da7SBart Van Assche struct srp_request *req = &ch->req_ring[j]; 1412509c07bcSBart Van Assche 1413509c07bcSBart Van Assche srp_finish_req(ch, req, NULL, DID_RESET << 16); 1414536ae14eSBart Van Assche } 1415d92c0da7SBart Van Assche } 1416d92c0da7SBart Van Assche for (i = 0; i < target->ch_count; i++) { 1417d92c0da7SBart Van Assche ch = &target->ch[i]; 14185cfb1782SBart Van Assche /* 14195cfb1782SBart Van Assche * Whether or not creating a new CM ID succeeded, create a new 1420d92c0da7SBart Van Assche * QP. This guarantees that all completion callback function 1421d92c0da7SBart Van Assche * invocations have finished before request resetting starts. 14225cfb1782SBart Van Assche */ 1423509c07bcSBart Van Assche ret += srp_create_ch_ib(ch); 14245cfb1782SBart Van Assche 1425509c07bcSBart Van Assche INIT_LIST_HEAD(&ch->free_tx); 1426d92c0da7SBart Van Assche for (j = 0; j < target->queue_size; ++j) 1427d92c0da7SBart Van Assche list_add(&ch->tx_ring[j]->list, &ch->free_tx); 1428d92c0da7SBart Van Assche } 14298de9fe3aSBart Van Assche 14308de9fe3aSBart Van Assche target->qp_in_error = false; 14318de9fe3aSBart Van Assche 1432d92c0da7SBart Van Assche for (i = 0; i < target->ch_count; i++) { 1433d92c0da7SBart Van Assche ch = &target->ch[i]; 1434bbac5ccfSBart Van Assche if (ret) 1435d92c0da7SBart Van Assche break; 1436513d5647SBart Van Assche ret = srp_connect_ch(ch, max_iu_len, multich); 1437d92c0da7SBart Van Assche multich = true; 1438d92c0da7SBart Van Assche } 143909be70a2SBart Van Assche 1440ed9b2264SBart Van Assche if (ret == 0) 1441ed9b2264SBart Van Assche shost_printk(KERN_INFO, target->scsi_host, 1442ed9b2264SBart Van Assche PFX "reconnect succeeded\n"); 1443aef9ec39SRoland Dreier 1444aef9ec39SRoland Dreier return ret; 1445aef9ec39SRoland Dreier } 1446aef9ec39SRoland Dreier 14478f26c9ffSDavid Dillow static void srp_map_desc(struct srp_map_state *state, dma_addr_t dma_addr, 14488f26c9ffSDavid Dillow unsigned int dma_len, u32 rkey) 1449f5358a17SRoland Dreier { 14508f26c9ffSDavid Dillow struct srp_direct_buf *desc = state->desc; 14518f26c9ffSDavid Dillow 14523ae95da8SBart Van Assche WARN_ON_ONCE(!dma_len); 14533ae95da8SBart Van Assche 14548f26c9ffSDavid Dillow desc->va = cpu_to_be64(dma_addr); 14558f26c9ffSDavid Dillow desc->key = cpu_to_be32(rkey); 14568f26c9ffSDavid Dillow desc->len = cpu_to_be32(dma_len); 14578f26c9ffSDavid Dillow 14588f26c9ffSDavid Dillow state->total_len += dma_len; 14598f26c9ffSDavid Dillow state->desc++; 14608f26c9ffSDavid Dillow state->ndesc++; 14618f26c9ffSDavid Dillow } 14628f26c9ffSDavid Dillow 14638f26c9ffSDavid Dillow static int srp_map_finish_fmr(struct srp_map_state *state, 1464509c07bcSBart Van Assche struct srp_rdma_ch *ch) 14658f26c9ffSDavid Dillow { 1466186fbc66SBart Van Assche struct srp_target_port *target = ch->target; 1467186fbc66SBart Van Assche struct srp_device *dev = target->srp_host->srp_dev; 14688f26c9ffSDavid Dillow struct ib_pool_fmr *fmr; 1469f5358a17SRoland Dreier u64 io_addr = 0; 14708f26c9ffSDavid Dillow 1471290081b4SBart Van Assche if (state->fmr.next >= state->fmr.end) { 1472290081b4SBart Van Assche shost_printk(KERN_ERR, ch->target->scsi_host, 1473290081b4SBart Van Assche PFX "Out of MRs (mr_per_cmd = %d)\n", 1474290081b4SBart Van Assche ch->target->mr_per_cmd); 1475f731ed62SBart Van Assche return -ENOMEM; 1476290081b4SBart Van Assche } 1477f731ed62SBart Van Assche 147826630e8aSSagi Grimberg WARN_ON_ONCE(!dev->use_fmr); 147926630e8aSSagi Grimberg 148026630e8aSSagi Grimberg if (state->npages == 0) 148126630e8aSSagi Grimberg return 0; 148226630e8aSSagi Grimberg 1483cee687b6SBart Van Assche if (state->npages == 1 && target->global_rkey) { 148426630e8aSSagi Grimberg srp_map_desc(state, state->base_dma_addr, state->dma_len, 1485cee687b6SBart Van Assche target->global_rkey); 148626630e8aSSagi Grimberg goto reset_state; 148726630e8aSSagi Grimberg } 148826630e8aSSagi Grimberg 1489509c07bcSBart Van Assche fmr = ib_fmr_pool_map_phys(ch->fmr_pool, state->pages, 14908f26c9ffSDavid Dillow state->npages, io_addr); 14918f26c9ffSDavid Dillow if (IS_ERR(fmr)) 14928f26c9ffSDavid Dillow return PTR_ERR(fmr); 14938f26c9ffSDavid Dillow 1494f731ed62SBart Van Assche *state->fmr.next++ = fmr; 149552ede08fSBart Van Assche state->nmdesc++; 14968f26c9ffSDavid Dillow 1497186fbc66SBart Van Assche srp_map_desc(state, state->base_dma_addr & ~dev->mr_page_mask, 1498186fbc66SBart Van Assche state->dma_len, fmr->fmr->rkey); 1499539dde6fSBart Van Assche 150026630e8aSSagi Grimberg reset_state: 150126630e8aSSagi Grimberg state->npages = 0; 150226630e8aSSagi Grimberg state->dma_len = 0; 150326630e8aSSagi Grimberg 15048f26c9ffSDavid Dillow return 0; 15058f26c9ffSDavid Dillow } 15068f26c9ffSDavid Dillow 15071dc7b1f1SChristoph Hellwig static void srp_reg_mr_err_done(struct ib_cq *cq, struct ib_wc *wc) 15081dc7b1f1SChristoph Hellwig { 15091dc7b1f1SChristoph Hellwig srp_handle_qp_err(cq, wc, "FAST REG"); 15101dc7b1f1SChristoph Hellwig } 15111dc7b1f1SChristoph Hellwig 1512509c5f33SBart Van Assche /* 1513509c5f33SBart Van Assche * Map up to sg_nents elements of state->sg where *sg_offset_p is the offset 1514509c5f33SBart Van Assche * where to start in the first element. If sg_offset_p != NULL then 1515509c5f33SBart Van Assche * *sg_offset_p is updated to the offset in state->sg[retval] of the first 1516509c5f33SBart Van Assche * byte that has not yet been mapped. 1517509c5f33SBart Van Assche */ 15185cfb1782SBart Van Assche static int srp_map_finish_fr(struct srp_map_state *state, 15191dc7b1f1SChristoph Hellwig struct srp_request *req, 1520509c5f33SBart Van Assche struct srp_rdma_ch *ch, int sg_nents, 1521509c5f33SBart Van Assche unsigned int *sg_offset_p) 15225cfb1782SBart Van Assche { 1523509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 15245cfb1782SBart Van Assche struct srp_device *dev = target->srp_host->srp_dev; 1525f7f7aab1SSagi Grimberg struct ib_reg_wr wr; 15265cfb1782SBart Van Assche struct srp_fr_desc *desc; 15275cfb1782SBart Van Assche u32 rkey; 1528f7f7aab1SSagi Grimberg int n, err; 15295cfb1782SBart Van Assche 1530290081b4SBart Van Assche if (state->fr.next >= state->fr.end) { 1531290081b4SBart Van Assche shost_printk(KERN_ERR, ch->target->scsi_host, 1532290081b4SBart Van Assche PFX "Out of MRs (mr_per_cmd = %d)\n", 1533290081b4SBart Van Assche ch->target->mr_per_cmd); 1534f731ed62SBart Van Assche return -ENOMEM; 1535290081b4SBart Van Assche } 1536f731ed62SBart Van Assche 153726630e8aSSagi Grimberg WARN_ON_ONCE(!dev->use_fast_reg); 153826630e8aSSagi Grimberg 1539cee687b6SBart Van Assche if (sg_nents == 1 && target->global_rkey) { 1540509c5f33SBart Van Assche unsigned int sg_offset = sg_offset_p ? *sg_offset_p : 0; 1541509c5f33SBart Van Assche 1542509c5f33SBart Van Assche srp_map_desc(state, sg_dma_address(state->sg) + sg_offset, 1543509c5f33SBart Van Assche sg_dma_len(state->sg) - sg_offset, 1544cee687b6SBart Van Assche target->global_rkey); 1545509c5f33SBart Van Assche if (sg_offset_p) 1546509c5f33SBart Van Assche *sg_offset_p = 0; 1547f7f7aab1SSagi Grimberg return 1; 154826630e8aSSagi Grimberg } 154926630e8aSSagi Grimberg 1550509c07bcSBart Van Assche desc = srp_fr_pool_get(ch->fr_pool); 15515cfb1782SBart Van Assche if (!desc) 15525cfb1782SBart Van Assche return -ENOMEM; 15535cfb1782SBart Van Assche 15545cfb1782SBart Van Assche rkey = ib_inc_rkey(desc->mr->rkey); 15555cfb1782SBart Van Assche ib_update_fast_reg_key(desc->mr, rkey); 15565cfb1782SBart Van Assche 1557509c5f33SBart Van Assche n = ib_map_mr_sg(desc->mr, state->sg, sg_nents, sg_offset_p, 1558509c5f33SBart Van Assche dev->mr_page_size); 15599d8e7d0dSBart Van Assche if (unlikely(n < 0)) { 15609d8e7d0dSBart Van Assche srp_fr_pool_put(ch->fr_pool, &desc, 1); 1561509c5f33SBart Van Assche pr_debug("%s: ib_map_mr_sg(%d, %d) returned %d.\n", 15629d8e7d0dSBart Van Assche dev_name(&req->scmnd->device->sdev_gendev), sg_nents, 1563509c5f33SBart Van Assche sg_offset_p ? *sg_offset_p : -1, n); 1564f7f7aab1SSagi Grimberg return n; 15659d8e7d0dSBart Van Assche } 15665cfb1782SBart Van Assche 1567509c5f33SBart Van Assche WARN_ON_ONCE(desc->mr->length == 0); 15685cfb1782SBart Van Assche 15691dc7b1f1SChristoph Hellwig req->reg_cqe.done = srp_reg_mr_err_done; 15701dc7b1f1SChristoph Hellwig 1571f7f7aab1SSagi Grimberg wr.wr.next = NULL; 1572f7f7aab1SSagi Grimberg wr.wr.opcode = IB_WR_REG_MR; 15731dc7b1f1SChristoph Hellwig wr.wr.wr_cqe = &req->reg_cqe; 1574f7f7aab1SSagi Grimberg wr.wr.num_sge = 0; 1575f7f7aab1SSagi Grimberg wr.wr.send_flags = 0; 1576f7f7aab1SSagi Grimberg wr.mr = desc->mr; 1577f7f7aab1SSagi Grimberg wr.key = desc->mr->rkey; 1578f7f7aab1SSagi Grimberg wr.access = (IB_ACCESS_LOCAL_WRITE | 15795cfb1782SBart Van Assche IB_ACCESS_REMOTE_READ | 15805cfb1782SBart Van Assche IB_ACCESS_REMOTE_WRITE); 15815cfb1782SBart Van Assche 1582f731ed62SBart Van Assche *state->fr.next++ = desc; 15835cfb1782SBart Van Assche state->nmdesc++; 15845cfb1782SBart Van Assche 1585f7f7aab1SSagi Grimberg srp_map_desc(state, desc->mr->iova, 1586f7f7aab1SSagi Grimberg desc->mr->length, desc->mr->rkey); 15875cfb1782SBart Van Assche 158871347b0cSBart Van Assche err = ib_post_send(ch->qp, &wr.wr, NULL); 1589509c5f33SBart Van Assche if (unlikely(err)) { 1590509c5f33SBart Van Assche WARN_ON_ONCE(err == -ENOMEM); 159126630e8aSSagi Grimberg return err; 1592509c5f33SBart Van Assche } 159326630e8aSSagi Grimberg 1594f7f7aab1SSagi Grimberg return n; 15955cfb1782SBart Van Assche } 15965cfb1782SBart Van Assche 15978f26c9ffSDavid Dillow static int srp_map_sg_entry(struct srp_map_state *state, 1598509c07bcSBart Van Assche struct srp_rdma_ch *ch, 159952bb8c62SBart Van Assche struct scatterlist *sg) 16008f26c9ffSDavid Dillow { 1601509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 160205321937SGreg Kroah-Hartman struct srp_device *dev = target->srp_host->srp_dev; 1603a163afc8SBart Van Assche dma_addr_t dma_addr = sg_dma_address(sg); 1604a163afc8SBart Van Assche unsigned int dma_len = sg_dma_len(sg); 16053ae95da8SBart Van Assche unsigned int len = 0; 16068f26c9ffSDavid Dillow int ret; 160785507bccSRalph Campbell 16083ae95da8SBart Van Assche WARN_ON_ONCE(!dma_len); 1609f5358a17SRoland Dreier 16108f26c9ffSDavid Dillow while (dma_len) { 16115cfb1782SBart Van Assche unsigned offset = dma_addr & ~dev->mr_page_mask; 1612681cc360SBart Van Assche 1613681cc360SBart Van Assche if (state->npages == dev->max_pages_per_mr || 1614681cc360SBart Van Assche (state->npages > 0 && offset != 0)) { 1615f7f7aab1SSagi Grimberg ret = srp_map_finish_fmr(state, ch); 16168f26c9ffSDavid Dillow if (ret) 16178f26c9ffSDavid Dillow return ret; 161885507bccSRalph Campbell } 1619f5358a17SRoland Dreier 16205cfb1782SBart Van Assche len = min_t(unsigned int, dma_len, dev->mr_page_size - offset); 16218f26c9ffSDavid Dillow 16228f26c9ffSDavid Dillow if (!state->npages) 16238f26c9ffSDavid Dillow state->base_dma_addr = dma_addr; 16245cfb1782SBart Van Assche state->pages[state->npages++] = dma_addr & dev->mr_page_mask; 162552ede08fSBart Van Assche state->dma_len += len; 16268f26c9ffSDavid Dillow dma_addr += len; 16278f26c9ffSDavid Dillow dma_len -= len; 1628f5358a17SRoland Dreier } 1629f5358a17SRoland Dreier 16305cfb1782SBart Van Assche /* 1631681cc360SBart Van Assche * If the end of the MR is not on a page boundary then we need to 16328f26c9ffSDavid Dillow * close it out and start a new one -- we can only merge at page 16331d3d98c4SBart Van Assche * boundaries. 16348f26c9ffSDavid Dillow */ 1635f5358a17SRoland Dreier ret = 0; 1636681cc360SBart Van Assche if ((dma_addr & ~dev->mr_page_mask) != 0) 1637f7f7aab1SSagi Grimberg ret = srp_map_finish_fmr(state, ch); 1638f5358a17SRoland Dreier return ret; 1639f5358a17SRoland Dreier } 1640f5358a17SRoland Dreier 164126630e8aSSagi Grimberg static int srp_map_sg_fmr(struct srp_map_state *state, struct srp_rdma_ch *ch, 164226630e8aSSagi Grimberg struct srp_request *req, struct scatterlist *scat, 164326630e8aSSagi Grimberg int count) 164426630e8aSSagi Grimberg { 164526630e8aSSagi Grimberg struct scatterlist *sg; 164626630e8aSSagi Grimberg int i, ret; 164726630e8aSSagi Grimberg 164826630e8aSSagi Grimberg state->pages = req->map_page; 164926630e8aSSagi Grimberg state->fmr.next = req->fmr_list; 1650509c5f33SBart Van Assche state->fmr.end = req->fmr_list + ch->target->mr_per_cmd; 165126630e8aSSagi Grimberg 165226630e8aSSagi Grimberg for_each_sg(scat, sg, count, i) { 165352bb8c62SBart Van Assche ret = srp_map_sg_entry(state, ch, sg); 165426630e8aSSagi Grimberg if (ret) 165526630e8aSSagi Grimberg return ret; 165626630e8aSSagi Grimberg } 165726630e8aSSagi Grimberg 1658f7f7aab1SSagi Grimberg ret = srp_map_finish_fmr(state, ch); 165926630e8aSSagi Grimberg if (ret) 166026630e8aSSagi Grimberg return ret; 166126630e8aSSagi Grimberg 166226630e8aSSagi Grimberg return 0; 166326630e8aSSagi Grimberg } 166426630e8aSSagi Grimberg 166526630e8aSSagi Grimberg static int srp_map_sg_fr(struct srp_map_state *state, struct srp_rdma_ch *ch, 166626630e8aSSagi Grimberg struct srp_request *req, struct scatterlist *scat, 166726630e8aSSagi Grimberg int count) 166826630e8aSSagi Grimberg { 1669509c5f33SBart Van Assche unsigned int sg_offset = 0; 1670509c5f33SBart Van Assche 1671f7f7aab1SSagi Grimberg state->fr.next = req->fr_list; 1672509c5f33SBart Van Assche state->fr.end = req->fr_list + ch->target->mr_per_cmd; 1673f7f7aab1SSagi Grimberg state->sg = scat; 167426630e8aSSagi Grimberg 16753b59b7a6SBart Van Assche if (count == 0) 16763b59b7a6SBart Van Assche return 0; 16773b59b7a6SBart Van Assche 167857b0be9cSBart Van Assche while (count) { 1679f7f7aab1SSagi Grimberg int i, n; 1680f7f7aab1SSagi Grimberg 1681509c5f33SBart Van Assche n = srp_map_finish_fr(state, req, ch, count, &sg_offset); 1682f7f7aab1SSagi Grimberg if (unlikely(n < 0)) 1683f7f7aab1SSagi Grimberg return n; 1684f7f7aab1SSagi Grimberg 168557b0be9cSBart Van Assche count -= n; 1686f7f7aab1SSagi Grimberg for (i = 0; i < n; i++) 1687f7f7aab1SSagi Grimberg state->sg = sg_next(state->sg); 168826630e8aSSagi Grimberg } 168926630e8aSSagi Grimberg 169026630e8aSSagi Grimberg return 0; 169126630e8aSSagi Grimberg } 169226630e8aSSagi Grimberg 169326630e8aSSagi Grimberg static int srp_map_sg_dma(struct srp_map_state *state, struct srp_rdma_ch *ch, 1694509c07bcSBart Van Assche struct srp_request *req, struct scatterlist *scat, 1695509c07bcSBart Van Assche int count) 169676bc1e1dSBart Van Assche { 1697509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 169876bc1e1dSBart Van Assche struct scatterlist *sg; 169926630e8aSSagi Grimberg int i; 170076bc1e1dSBart Van Assche 17013ae95da8SBart Van Assche for_each_sg(scat, sg, count, i) { 1702a163afc8SBart Van Assche srp_map_desc(state, sg_dma_address(sg), sg_dma_len(sg), 1703cee687b6SBart Van Assche target->global_rkey); 17043ae95da8SBart Van Assche } 170576bc1e1dSBart Van Assche 170626630e8aSSagi Grimberg return 0; 170776bc1e1dSBart Van Assche } 170876bc1e1dSBart Van Assche 1709330179f2SBart Van Assche /* 1710330179f2SBart Van Assche * Register the indirect data buffer descriptor with the HCA. 1711330179f2SBart Van Assche * 1712330179f2SBart Van Assche * Note: since the indirect data buffer descriptor has been allocated with 1713330179f2SBart Van Assche * kmalloc() it is guaranteed that this buffer is a physically contiguous 1714330179f2SBart Van Assche * memory buffer. 1715330179f2SBart Van Assche */ 1716330179f2SBart Van Assche static int srp_map_idb(struct srp_rdma_ch *ch, struct srp_request *req, 1717330179f2SBart Van Assche void **next_mr, void **end_mr, u32 idb_len, 1718330179f2SBart Van Assche __be32 *idb_rkey) 1719330179f2SBart Van Assche { 1720330179f2SBart Van Assche struct srp_target_port *target = ch->target; 1721330179f2SBart Van Assche struct srp_device *dev = target->srp_host->srp_dev; 1722330179f2SBart Van Assche struct srp_map_state state; 1723330179f2SBart Van Assche struct srp_direct_buf idb_desc; 1724330179f2SBart Van Assche u64 idb_pages[1]; 1725f7f7aab1SSagi Grimberg struct scatterlist idb_sg[1]; 1726330179f2SBart Van Assche int ret; 1727330179f2SBart Van Assche 1728330179f2SBart Van Assche memset(&state, 0, sizeof(state)); 1729330179f2SBart Van Assche memset(&idb_desc, 0, sizeof(idb_desc)); 1730330179f2SBart Van Assche state.gen.next = next_mr; 1731330179f2SBart Van Assche state.gen.end = end_mr; 1732330179f2SBart Van Assche state.desc = &idb_desc; 1733f7f7aab1SSagi Grimberg state.base_dma_addr = req->indirect_dma_addr; 1734f7f7aab1SSagi Grimberg state.dma_len = idb_len; 1735f7f7aab1SSagi Grimberg 1736f7f7aab1SSagi Grimberg if (dev->use_fast_reg) { 1737f7f7aab1SSagi Grimberg state.sg = idb_sg; 173854f5c9c5SBart Van Assche sg_init_one(idb_sg, req->indirect_desc, idb_len); 1739f7f7aab1SSagi Grimberg idb_sg->dma_address = req->indirect_dma_addr; /* hack! */ 1740fc925518SChristoph Hellwig #ifdef CONFIG_NEED_SG_DMA_LENGTH 1741fc925518SChristoph Hellwig idb_sg->dma_length = idb_sg->length; /* hack^2 */ 1742fc925518SChristoph Hellwig #endif 1743509c5f33SBart Van Assche ret = srp_map_finish_fr(&state, req, ch, 1, NULL); 1744f7f7aab1SSagi Grimberg if (ret < 0) 1745f7f7aab1SSagi Grimberg return ret; 1746509c5f33SBart Van Assche WARN_ON_ONCE(ret < 1); 1747f7f7aab1SSagi Grimberg } else if (dev->use_fmr) { 1748330179f2SBart Van Assche state.pages = idb_pages; 1749330179f2SBart Van Assche state.pages[0] = (req->indirect_dma_addr & 1750330179f2SBart Van Assche dev->mr_page_mask); 1751330179f2SBart Van Assche state.npages = 1; 1752f7f7aab1SSagi Grimberg ret = srp_map_finish_fmr(&state, ch); 1753330179f2SBart Van Assche if (ret < 0) 1754f7f7aab1SSagi Grimberg return ret; 1755f7f7aab1SSagi Grimberg } else { 1756f7f7aab1SSagi Grimberg return -EINVAL; 1757f7f7aab1SSagi Grimberg } 1758330179f2SBart Van Assche 1759330179f2SBart Van Assche *idb_rkey = idb_desc.key; 1760330179f2SBart Van Assche 1761f7f7aab1SSagi Grimberg return 0; 1762330179f2SBart Van Assche } 1763330179f2SBart Van Assche 1764509c5f33SBart Van Assche static void srp_check_mapping(struct srp_map_state *state, 1765509c5f33SBart Van Assche struct srp_rdma_ch *ch, struct srp_request *req, 1766509c5f33SBart Van Assche struct scatterlist *scat, int count) 1767509c5f33SBart Van Assche { 1768509c5f33SBart Van Assche struct srp_device *dev = ch->target->srp_host->srp_dev; 1769509c5f33SBart Van Assche struct srp_fr_desc **pfr; 1770509c5f33SBart Van Assche u64 desc_len = 0, mr_len = 0; 1771509c5f33SBart Van Assche int i; 1772509c5f33SBart Van Assche 1773509c5f33SBart Van Assche for (i = 0; i < state->ndesc; i++) 1774509c5f33SBart Van Assche desc_len += be32_to_cpu(req->indirect_desc[i].len); 1775509c5f33SBart Van Assche if (dev->use_fast_reg) 1776509c5f33SBart Van Assche for (i = 0, pfr = req->fr_list; i < state->nmdesc; i++, pfr++) 1777509c5f33SBart Van Assche mr_len += (*pfr)->mr->length; 1778509c5f33SBart Van Assche else if (dev->use_fmr) 1779509c5f33SBart Van Assche for (i = 0; i < state->nmdesc; i++) 1780509c5f33SBart Van Assche mr_len += be32_to_cpu(req->indirect_desc[i].len); 1781509c5f33SBart Van Assche if (desc_len != scsi_bufflen(req->scmnd) || 1782509c5f33SBart Van Assche mr_len > scsi_bufflen(req->scmnd)) 1783509c5f33SBart Van Assche pr_err("Inconsistent: scsi len %d <> desc len %lld <> mr len %lld; ndesc %d; nmdesc = %d\n", 1784509c5f33SBart Van Assche scsi_bufflen(req->scmnd), desc_len, mr_len, 1785509c5f33SBart Van Assche state->ndesc, state->nmdesc); 1786509c5f33SBart Van Assche } 1787509c5f33SBart Van Assche 178877269cdfSBart Van Assche /** 178977269cdfSBart Van Assche * srp_map_data() - map SCSI data buffer onto an SRP request 179077269cdfSBart Van Assche * @scmnd: SCSI command to map 179177269cdfSBart Van Assche * @ch: SRP RDMA channel 179277269cdfSBart Van Assche * @req: SRP request 179377269cdfSBart Van Assche * 179477269cdfSBart Van Assche * Returns the length in bytes of the SRP_CMD IU or a negative value if 1795882981f4SBart Van Assche * mapping failed. The size of any immediate data is not included in the 1796882981f4SBart Van Assche * return value. 179777269cdfSBart Van Assche */ 1798509c07bcSBart Van Assche static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_rdma_ch *ch, 1799aef9ec39SRoland Dreier struct srp_request *req) 1800aef9ec39SRoland Dreier { 1801509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 1802882981f4SBart Van Assche struct scatterlist *scat, *sg; 1803aef9ec39SRoland Dreier struct srp_cmd *cmd = req->cmd->buf; 1804882981f4SBart Van Assche int i, len, nents, count, ret; 180585507bccSRalph Campbell struct srp_device *dev; 180685507bccSRalph Campbell struct ib_device *ibdev; 18078f26c9ffSDavid Dillow struct srp_map_state state; 18088f26c9ffSDavid Dillow struct srp_indirect_buf *indirect_hdr; 1809882981f4SBart Van Assche u64 data_len; 1810330179f2SBart Van Assche u32 idb_len, table_len; 1811330179f2SBart Van Assche __be32 idb_rkey; 18128f26c9ffSDavid Dillow u8 fmt; 1813aef9ec39SRoland Dreier 1814882981f4SBart Van Assche req->cmd->num_sge = 1; 1815882981f4SBart Van Assche 1816bb350d1dSFUJITA Tomonori if (!scsi_sglist(scmnd) || scmnd->sc_data_direction == DMA_NONE) 1817482fffc4SBart Van Assche return sizeof(struct srp_cmd) + cmd->add_cdb_len; 1818aef9ec39SRoland Dreier 1819aef9ec39SRoland Dreier if (scmnd->sc_data_direction != DMA_FROM_DEVICE && 1820aef9ec39SRoland Dreier scmnd->sc_data_direction != DMA_TO_DEVICE) { 18217aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 18227aa54bd7SDavid Dillow PFX "Unhandled data direction %d\n", 1823aef9ec39SRoland Dreier scmnd->sc_data_direction); 1824aef9ec39SRoland Dreier return -EINVAL; 1825aef9ec39SRoland Dreier } 1826aef9ec39SRoland Dreier 1827bb350d1dSFUJITA Tomonori nents = scsi_sg_count(scmnd); 1828bb350d1dSFUJITA Tomonori scat = scsi_sglist(scmnd); 1829882981f4SBart Van Assche data_len = scsi_bufflen(scmnd); 1830aef9ec39SRoland Dreier 183105321937SGreg Kroah-Hartman dev = target->srp_host->srp_dev; 183285507bccSRalph Campbell ibdev = dev->dev; 183385507bccSRalph Campbell 183485507bccSRalph Campbell count = ib_dma_map_sg(ibdev, scat, nents, scmnd->sc_data_direction); 18358f26c9ffSDavid Dillow if (unlikely(count == 0)) 18368f26c9ffSDavid Dillow return -EIO; 1837aef9ec39SRoland Dreier 1838882981f4SBart Van Assche if (ch->use_imm_data && 1839882981f4SBart Van Assche count <= SRP_MAX_IMM_SGE && 1840882981f4SBart Van Assche SRP_IMM_DATA_OFFSET + data_len <= ch->max_it_iu_len && 1841882981f4SBart Van Assche scmnd->sc_data_direction == DMA_TO_DEVICE) { 1842882981f4SBart Van Assche struct srp_imm_buf *buf; 1843882981f4SBart Van Assche struct ib_sge *sge = &req->cmd->sge[1]; 1844882981f4SBart Van Assche 1845882981f4SBart Van Assche fmt = SRP_DATA_DESC_IMM; 1846882981f4SBart Van Assche len = SRP_IMM_DATA_OFFSET; 1847882981f4SBart Van Assche req->nmdesc = 0; 1848882981f4SBart Van Assche buf = (void *)cmd->add_data + cmd->add_cdb_len; 1849882981f4SBart Van Assche buf->len = cpu_to_be32(data_len); 1850882981f4SBart Van Assche WARN_ON_ONCE((void *)(buf + 1) > (void *)cmd + len); 1851882981f4SBart Van Assche for_each_sg(scat, sg, count, i) { 1852a163afc8SBart Van Assche sge[i].addr = sg_dma_address(sg); 1853a163afc8SBart Van Assche sge[i].length = sg_dma_len(sg); 1854882981f4SBart Van Assche sge[i].lkey = target->lkey; 1855882981f4SBart Van Assche } 1856882981f4SBart Van Assche req->cmd->num_sge += count; 1857882981f4SBart Van Assche goto map_complete; 1858882981f4SBart Van Assche } 1859882981f4SBart Van Assche 1860aef9ec39SRoland Dreier fmt = SRP_DATA_DESC_DIRECT; 1861482fffc4SBart Van Assche len = sizeof(struct srp_cmd) + cmd->add_cdb_len + 1862482fffc4SBart Van Assche sizeof(struct srp_direct_buf); 1863f5358a17SRoland Dreier 1864cee687b6SBart Van Assche if (count == 1 && target->global_rkey) { 1865f5358a17SRoland Dreier /* 1866f5358a17SRoland Dreier * The midlayer only generated a single gather/scatter 1867f5358a17SRoland Dreier * entry, or DMA mapping coalesced everything to a 1868f5358a17SRoland Dreier * single entry. So a direct descriptor along with 1869f5358a17SRoland Dreier * the DMA MR suffices. 1870f5358a17SRoland Dreier */ 1871482fffc4SBart Van Assche struct srp_direct_buf *buf; 1872aef9ec39SRoland Dreier 1873482fffc4SBart Van Assche buf = (void *)cmd->add_data + cmd->add_cdb_len; 1874a163afc8SBart Van Assche buf->va = cpu_to_be64(sg_dma_address(scat)); 1875cee687b6SBart Van Assche buf->key = cpu_to_be32(target->global_rkey); 1876a163afc8SBart Van Assche buf->len = cpu_to_be32(sg_dma_len(scat)); 18778f26c9ffSDavid Dillow 187852ede08fSBart Van Assche req->nmdesc = 0; 18798f26c9ffSDavid Dillow goto map_complete; 18808f26c9ffSDavid Dillow } 18818f26c9ffSDavid Dillow 18825cfb1782SBart Van Assche /* 18835cfb1782SBart Van Assche * We have more than one scatter/gather entry, so build our indirect 18845cfb1782SBart Van Assche * descriptor table, trying to merge as many entries as we can. 1885f5358a17SRoland Dreier */ 1886482fffc4SBart Van Assche indirect_hdr = (void *)cmd->add_data + cmd->add_cdb_len; 18878f26c9ffSDavid Dillow 1888c07d424dSDavid Dillow ib_dma_sync_single_for_cpu(ibdev, req->indirect_dma_addr, 1889c07d424dSDavid Dillow target->indirect_size, DMA_TO_DEVICE); 1890c07d424dSDavid Dillow 18918f26c9ffSDavid Dillow memset(&state, 0, sizeof(state)); 18929edba790SBart Van Assche state.desc = req->indirect_desc; 189326630e8aSSagi Grimberg if (dev->use_fast_reg) 1894e012f363SBart Van Assche ret = srp_map_sg_fr(&state, ch, req, scat, count); 189526630e8aSSagi Grimberg else if (dev->use_fmr) 1896e012f363SBart Van Assche ret = srp_map_sg_fmr(&state, ch, req, scat, count); 189726630e8aSSagi Grimberg else 1898e012f363SBart Van Assche ret = srp_map_sg_dma(&state, ch, req, scat, count); 1899e012f363SBart Van Assche req->nmdesc = state.nmdesc; 1900e012f363SBart Van Assche if (ret < 0) 1901e012f363SBart Van Assche goto unmap; 19028f26c9ffSDavid Dillow 1903509c5f33SBart Van Assche { 1904509c5f33SBart Van Assche DEFINE_DYNAMIC_DEBUG_METADATA(ddm, 1905509c5f33SBart Van Assche "Memory mapping consistency check"); 19061a1faf7aSBart Van Assche if (DYNAMIC_DEBUG_BRANCH(ddm)) 1907509c5f33SBart Van Assche srp_check_mapping(&state, ch, req, scat, count); 1908509c5f33SBart Van Assche } 19098f26c9ffSDavid Dillow 1910c07d424dSDavid Dillow /* We've mapped the request, now pull as much of the indirect 1911c07d424dSDavid Dillow * descriptor table as we can into the command buffer. If this 1912c07d424dSDavid Dillow * target is not using an external indirect table, we are 1913c07d424dSDavid Dillow * guaranteed to fit into the command, as the SCSI layer won't 1914c07d424dSDavid Dillow * give us more S/G entries than we allow. 19158f26c9ffSDavid Dillow */ 19168f26c9ffSDavid Dillow if (state.ndesc == 1) { 19175cfb1782SBart Van Assche /* 19185cfb1782SBart Van Assche * Memory registration collapsed the sg-list into one entry, 19198f26c9ffSDavid Dillow * so use a direct descriptor. 19208f26c9ffSDavid Dillow */ 1921482fffc4SBart Van Assche struct srp_direct_buf *buf; 19228f26c9ffSDavid Dillow 1923482fffc4SBart Van Assche buf = (void *)cmd->add_data + cmd->add_cdb_len; 1924c07d424dSDavid Dillow *buf = req->indirect_desc[0]; 19258f26c9ffSDavid Dillow goto map_complete; 19268f26c9ffSDavid Dillow } 19278f26c9ffSDavid Dillow 1928c07d424dSDavid Dillow if (unlikely(target->cmd_sg_cnt < state.ndesc && 1929c07d424dSDavid Dillow !target->allow_ext_sg)) { 1930c07d424dSDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 1931c07d424dSDavid Dillow "Could not fit S/G list into SRP_CMD\n"); 1932e012f363SBart Van Assche ret = -EIO; 1933e012f363SBart Van Assche goto unmap; 1934c07d424dSDavid Dillow } 1935c07d424dSDavid Dillow 1936c07d424dSDavid Dillow count = min(state.ndesc, target->cmd_sg_cnt); 19378f26c9ffSDavid Dillow table_len = state.ndesc * sizeof (struct srp_direct_buf); 1938330179f2SBart Van Assche idb_len = sizeof(struct srp_indirect_buf) + table_len; 1939aef9ec39SRoland Dreier 1940aef9ec39SRoland Dreier fmt = SRP_DATA_DESC_INDIRECT; 1941482fffc4SBart Van Assche len = sizeof(struct srp_cmd) + cmd->add_cdb_len + 1942482fffc4SBart Van Assche sizeof(struct srp_indirect_buf); 1943c07d424dSDavid Dillow len += count * sizeof (struct srp_direct_buf); 1944f5358a17SRoland Dreier 1945c07d424dSDavid Dillow memcpy(indirect_hdr->desc_list, req->indirect_desc, 1946c07d424dSDavid Dillow count * sizeof (struct srp_direct_buf)); 194785507bccSRalph Campbell 1948cee687b6SBart Van Assche if (!target->global_rkey) { 1949330179f2SBart Van Assche ret = srp_map_idb(ch, req, state.gen.next, state.gen.end, 1950330179f2SBart Van Assche idb_len, &idb_rkey); 1951330179f2SBart Van Assche if (ret < 0) 1952e012f363SBart Van Assche goto unmap; 1953330179f2SBart Van Assche req->nmdesc++; 1954330179f2SBart Van Assche } else { 1955cee687b6SBart Van Assche idb_rkey = cpu_to_be32(target->global_rkey); 1956330179f2SBart Van Assche } 1957330179f2SBart Van Assche 1958c07d424dSDavid Dillow indirect_hdr->table_desc.va = cpu_to_be64(req->indirect_dma_addr); 1959330179f2SBart Van Assche indirect_hdr->table_desc.key = idb_rkey; 19608f26c9ffSDavid Dillow indirect_hdr->table_desc.len = cpu_to_be32(table_len); 19618f26c9ffSDavid Dillow indirect_hdr->len = cpu_to_be32(state.total_len); 1962aef9ec39SRoland Dreier 1963aef9ec39SRoland Dreier if (scmnd->sc_data_direction == DMA_TO_DEVICE) 1964c07d424dSDavid Dillow cmd->data_out_desc_cnt = count; 1965aef9ec39SRoland Dreier else 1966c07d424dSDavid Dillow cmd->data_in_desc_cnt = count; 1967c07d424dSDavid Dillow 1968c07d424dSDavid Dillow ib_dma_sync_single_for_device(ibdev, req->indirect_dma_addr, table_len, 1969c07d424dSDavid Dillow DMA_TO_DEVICE); 1970aef9ec39SRoland Dreier 19718f26c9ffSDavid Dillow map_complete: 1972aef9ec39SRoland Dreier if (scmnd->sc_data_direction == DMA_TO_DEVICE) 1973aef9ec39SRoland Dreier cmd->buf_fmt = fmt << 4; 1974aef9ec39SRoland Dreier else 1975aef9ec39SRoland Dreier cmd->buf_fmt = fmt; 1976aef9ec39SRoland Dreier 1977aef9ec39SRoland Dreier return len; 1978e012f363SBart Van Assche 1979e012f363SBart Van Assche unmap: 1980e012f363SBart Van Assche srp_unmap_data(scmnd, ch, req); 1981ffc548bbSBart Van Assche if (ret == -ENOMEM && req->nmdesc >= target->mr_pool_size) 1982ffc548bbSBart Van Assche ret = -E2BIG; 1983e012f363SBart Van Assche return ret; 1984aef9ec39SRoland Dreier } 1985aef9ec39SRoland Dreier 198605a1d750SDavid Dillow /* 198776c75b25SBart Van Assche * Return an IU and possible credit to the free pool 198876c75b25SBart Van Assche */ 1989509c07bcSBart Van Assche static void srp_put_tx_iu(struct srp_rdma_ch *ch, struct srp_iu *iu, 199076c75b25SBart Van Assche enum srp_iu_type iu_type) 199176c75b25SBart Van Assche { 199276c75b25SBart Van Assche unsigned long flags; 199376c75b25SBart Van Assche 1994509c07bcSBart Van Assche spin_lock_irqsave(&ch->lock, flags); 1995509c07bcSBart Van Assche list_add(&iu->list, &ch->free_tx); 199676c75b25SBart Van Assche if (iu_type != SRP_IU_RSP) 1997509c07bcSBart Van Assche ++ch->req_lim; 1998509c07bcSBart Van Assche spin_unlock_irqrestore(&ch->lock, flags); 199976c75b25SBart Van Assche } 200076c75b25SBart Van Assche 200176c75b25SBart Van Assche /* 2002509c07bcSBart Van Assche * Must be called with ch->lock held to protect req_lim and free_tx. 2003e9684678SBart Van Assche * If IU is not sent, it must be returned using srp_put_tx_iu(). 200405a1d750SDavid Dillow * 200505a1d750SDavid Dillow * Note: 200605a1d750SDavid Dillow * An upper limit for the number of allocated information units for each 200705a1d750SDavid Dillow * request type is: 200805a1d750SDavid Dillow * - SRP_IU_CMD: SRP_CMD_SQ_SIZE, since the SCSI mid-layer never queues 200905a1d750SDavid Dillow * more than Scsi_Host.can_queue requests. 201005a1d750SDavid Dillow * - SRP_IU_TSK_MGMT: SRP_TSK_MGMT_SQ_SIZE. 201105a1d750SDavid Dillow * - SRP_IU_RSP: 1, since a conforming SRP target never sends more than 201205a1d750SDavid Dillow * one unanswered SRP request to an initiator. 201305a1d750SDavid Dillow */ 2014509c07bcSBart Van Assche static struct srp_iu *__srp_get_tx_iu(struct srp_rdma_ch *ch, 201505a1d750SDavid Dillow enum srp_iu_type iu_type) 201605a1d750SDavid Dillow { 2017509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 201805a1d750SDavid Dillow s32 rsv = (iu_type == SRP_IU_TSK_MGMT) ? 0 : SRP_TSK_MGMT_SQ_SIZE; 201905a1d750SDavid Dillow struct srp_iu *iu; 202005a1d750SDavid Dillow 202193c76dbbSBart Van Assche lockdep_assert_held(&ch->lock); 202293c76dbbSBart Van Assche 20231dc7b1f1SChristoph Hellwig ib_process_cq_direct(ch->send_cq, -1); 202405a1d750SDavid Dillow 2025509c07bcSBart Van Assche if (list_empty(&ch->free_tx)) 202605a1d750SDavid Dillow return NULL; 202705a1d750SDavid Dillow 202805a1d750SDavid Dillow /* Initiator responses to target requests do not consume credits */ 202976c75b25SBart Van Assche if (iu_type != SRP_IU_RSP) { 2030509c07bcSBart Van Assche if (ch->req_lim <= rsv) { 203105a1d750SDavid Dillow ++target->zero_req_lim; 203205a1d750SDavid Dillow return NULL; 203305a1d750SDavid Dillow } 203405a1d750SDavid Dillow 2035509c07bcSBart Van Assche --ch->req_lim; 203676c75b25SBart Van Assche } 203776c75b25SBart Van Assche 2038509c07bcSBart Van Assche iu = list_first_entry(&ch->free_tx, struct srp_iu, list); 203976c75b25SBart Van Assche list_del(&iu->list); 204005a1d750SDavid Dillow return iu; 204105a1d750SDavid Dillow } 204205a1d750SDavid Dillow 20439294000dSBart Van Assche /* 20449294000dSBart Van Assche * Note: if this function is called from inside ib_drain_sq() then it will 20459294000dSBart Van Assche * be called without ch->lock being held. If ib_drain_sq() dequeues a WQE 20469294000dSBart Van Assche * with status IB_WC_SUCCESS then that's a bug. 20479294000dSBart Van Assche */ 20481dc7b1f1SChristoph Hellwig static void srp_send_done(struct ib_cq *cq, struct ib_wc *wc) 20491dc7b1f1SChristoph Hellwig { 20501dc7b1f1SChristoph Hellwig struct srp_iu *iu = container_of(wc->wr_cqe, struct srp_iu, cqe); 20511dc7b1f1SChristoph Hellwig struct srp_rdma_ch *ch = cq->cq_context; 20521dc7b1f1SChristoph Hellwig 20531dc7b1f1SChristoph Hellwig if (unlikely(wc->status != IB_WC_SUCCESS)) { 20541dc7b1f1SChristoph Hellwig srp_handle_qp_err(cq, wc, "SEND"); 20551dc7b1f1SChristoph Hellwig return; 20561dc7b1f1SChristoph Hellwig } 20571dc7b1f1SChristoph Hellwig 205893c76dbbSBart Van Assche lockdep_assert_held(&ch->lock); 205993c76dbbSBart Van Assche 20601dc7b1f1SChristoph Hellwig list_add(&iu->list, &ch->free_tx); 20611dc7b1f1SChristoph Hellwig } 20621dc7b1f1SChristoph Hellwig 2063882981f4SBart Van Assche /** 2064882981f4SBart Van Assche * srp_post_send() - send an SRP information unit 2065882981f4SBart Van Assche * @ch: RDMA channel over which to send the information unit. 2066882981f4SBart Van Assche * @iu: Information unit to send. 2067882981f4SBart Van Assche * @len: Length of the information unit excluding immediate data. 2068882981f4SBart Van Assche */ 2069509c07bcSBart Van Assche static int srp_post_send(struct srp_rdma_ch *ch, struct srp_iu *iu, int len) 207005a1d750SDavid Dillow { 2071509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 207271347b0cSBart Van Assche struct ib_send_wr wr; 207305a1d750SDavid Dillow 2074882981f4SBart Van Assche if (WARN_ON_ONCE(iu->num_sge > SRP_MAX_SGE)) 2075882981f4SBart Van Assche return -EINVAL; 2076882981f4SBart Van Assche 2077882981f4SBart Van Assche iu->sge[0].addr = iu->dma; 2078882981f4SBart Van Assche iu->sge[0].length = len; 2079882981f4SBart Van Assche iu->sge[0].lkey = target->lkey; 208005a1d750SDavid Dillow 20811dc7b1f1SChristoph Hellwig iu->cqe.done = srp_send_done; 20821dc7b1f1SChristoph Hellwig 208305a1d750SDavid Dillow wr.next = NULL; 20841dc7b1f1SChristoph Hellwig wr.wr_cqe = &iu->cqe; 2085882981f4SBart Van Assche wr.sg_list = &iu->sge[0]; 2086882981f4SBart Van Assche wr.num_sge = iu->num_sge; 208705a1d750SDavid Dillow wr.opcode = IB_WR_SEND; 208805a1d750SDavid Dillow wr.send_flags = IB_SEND_SIGNALED; 208905a1d750SDavid Dillow 209071347b0cSBart Van Assche return ib_post_send(ch->qp, &wr, NULL); 209105a1d750SDavid Dillow } 209205a1d750SDavid Dillow 2093509c07bcSBart Van Assche static int srp_post_recv(struct srp_rdma_ch *ch, struct srp_iu *iu) 2094c996bb47SBart Van Assche { 2095509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 209671347b0cSBart Van Assche struct ib_recv_wr wr; 2097dcb4cb85SBart Van Assche struct ib_sge list; 2098c996bb47SBart Van Assche 2099c996bb47SBart Van Assche list.addr = iu->dma; 2100c996bb47SBart Van Assche list.length = iu->size; 21019af76271SDavid Dillow list.lkey = target->lkey; 2102c996bb47SBart Van Assche 21031dc7b1f1SChristoph Hellwig iu->cqe.done = srp_recv_done; 21041dc7b1f1SChristoph Hellwig 2105c996bb47SBart Van Assche wr.next = NULL; 21061dc7b1f1SChristoph Hellwig wr.wr_cqe = &iu->cqe; 2107c996bb47SBart Van Assche wr.sg_list = &list; 2108c996bb47SBart Van Assche wr.num_sge = 1; 2109c996bb47SBart Van Assche 211071347b0cSBart Van Assche return ib_post_recv(ch->qp, &wr, NULL); 2111c996bb47SBart Van Assche } 2112c996bb47SBart Van Assche 2113509c07bcSBart Van Assche static void srp_process_rsp(struct srp_rdma_ch *ch, struct srp_rsp *rsp) 2114aef9ec39SRoland Dreier { 2115509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 2116aef9ec39SRoland Dreier struct srp_request *req; 2117aef9ec39SRoland Dreier struct scsi_cmnd *scmnd; 2118aef9ec39SRoland Dreier unsigned long flags; 2119aef9ec39SRoland Dreier 2120aef9ec39SRoland Dreier if (unlikely(rsp->tag & SRP_TAG_TSK_MGMT)) { 2121509c07bcSBart Van Assche spin_lock_irqsave(&ch->lock, flags); 2122509c07bcSBart Van Assche ch->req_lim += be32_to_cpu(rsp->req_lim_delta); 21230a6fdbdeSBart Van Assche if (rsp->tag == ch->tsk_mgmt_tag) { 2124509c07bcSBart Van Assche ch->tsk_mgmt_status = -1; 2125f8b6e31eSDavid Dillow if (be32_to_cpu(rsp->resp_data_len) >= 4) 2126509c07bcSBart Van Assche ch->tsk_mgmt_status = rsp->data[3]; 2127509c07bcSBart Van Assche complete(&ch->tsk_mgmt_done); 2128aef9ec39SRoland Dreier } else { 21290a6fdbdeSBart Van Assche shost_printk(KERN_ERR, target->scsi_host, 21300a6fdbdeSBart Van Assche "Received tsk mgmt response too late for tag %#llx\n", 21310a6fdbdeSBart Van Assche rsp->tag); 21320a6fdbdeSBart Van Assche } 21330a6fdbdeSBart Van Assche spin_unlock_irqrestore(&ch->lock, flags); 21340a6fdbdeSBart Van Assche } else { 213577f2c1a4SBart Van Assche scmnd = scsi_host_find_tag(target->scsi_host, rsp->tag); 21366cb72bc1SBart Van Assche if (scmnd && scmnd->host_scribble) { 213777f2c1a4SBart Van Assche req = (void *)scmnd->host_scribble; 213877f2c1a4SBart Van Assche scmnd = srp_claim_req(ch, req, NULL, scmnd); 21396cb72bc1SBart Van Assche } else { 21406cb72bc1SBart Van Assche scmnd = NULL; 214177f2c1a4SBart Van Assche } 214222032991SBart Van Assche if (!scmnd) { 21437aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 2144d92c0da7SBart Van Assche "Null scmnd for RSP w/tag %#016llx received on ch %td / QP %#x\n", 2145d92c0da7SBart Van Assche rsp->tag, ch - target->ch, ch->qp->qp_num); 214622032991SBart Van Assche 2147509c07bcSBart Van Assche spin_lock_irqsave(&ch->lock, flags); 2148509c07bcSBart Van Assche ch->req_lim += be32_to_cpu(rsp->req_lim_delta); 2149509c07bcSBart Van Assche spin_unlock_irqrestore(&ch->lock, flags); 215022032991SBart Van Assche 215122032991SBart Van Assche return; 215222032991SBart Van Assche } 2153aef9ec39SRoland Dreier scmnd->result = rsp->status; 2154aef9ec39SRoland Dreier 2155aef9ec39SRoland Dreier if (rsp->flags & SRP_RSP_FLAG_SNSVALID) { 2156aef9ec39SRoland Dreier memcpy(scmnd->sense_buffer, rsp->data + 2157aef9ec39SRoland Dreier be32_to_cpu(rsp->resp_data_len), 2158aef9ec39SRoland Dreier min_t(int, be32_to_cpu(rsp->sense_data_len), 2159aef9ec39SRoland Dreier SCSI_SENSE_BUFFERSIZE)); 2160aef9ec39SRoland Dreier } 2161aef9ec39SRoland Dreier 2162e714531aSBart Van Assche if (unlikely(rsp->flags & SRP_RSP_FLAG_DIUNDER)) 2163bb350d1dSFUJITA Tomonori scsi_set_resid(scmnd, be32_to_cpu(rsp->data_in_res_cnt)); 2164e714531aSBart Van Assche else if (unlikely(rsp->flags & SRP_RSP_FLAG_DIOVER)) 2165e714531aSBart Van Assche scsi_set_resid(scmnd, -be32_to_cpu(rsp->data_in_res_cnt)); 2166e714531aSBart Van Assche else if (unlikely(rsp->flags & SRP_RSP_FLAG_DOUNDER)) 2167e714531aSBart Van Assche scsi_set_resid(scmnd, be32_to_cpu(rsp->data_out_res_cnt)); 2168e714531aSBart Van Assche else if (unlikely(rsp->flags & SRP_RSP_FLAG_DOOVER)) 2169e714531aSBart Van Assche scsi_set_resid(scmnd, -be32_to_cpu(rsp->data_out_res_cnt)); 2170aef9ec39SRoland Dreier 2171509c07bcSBart Van Assche srp_free_req(ch, req, scmnd, 217222032991SBart Van Assche be32_to_cpu(rsp->req_lim_delta)); 217322032991SBart Van Assche 2174f8b6e31eSDavid Dillow scmnd->host_scribble = NULL; 2175aef9ec39SRoland Dreier scmnd->scsi_done(scmnd); 2176aef9ec39SRoland Dreier } 2177aef9ec39SRoland Dreier } 2178aef9ec39SRoland Dreier 2179509c07bcSBart Van Assche static int srp_response_common(struct srp_rdma_ch *ch, s32 req_delta, 2180bb12588aSDavid Dillow void *rsp, int len) 2181bb12588aSDavid Dillow { 2182509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 218376c75b25SBart Van Assche struct ib_device *dev = target->srp_host->srp_dev->dev; 2184bb12588aSDavid Dillow unsigned long flags; 2185bb12588aSDavid Dillow struct srp_iu *iu; 218676c75b25SBart Van Assche int err; 2187bb12588aSDavid Dillow 2188509c07bcSBart Van Assche spin_lock_irqsave(&ch->lock, flags); 2189509c07bcSBart Van Assche ch->req_lim += req_delta; 2190509c07bcSBart Van Assche iu = __srp_get_tx_iu(ch, SRP_IU_RSP); 2191509c07bcSBart Van Assche spin_unlock_irqrestore(&ch->lock, flags); 219276c75b25SBart Van Assche 2193bb12588aSDavid Dillow if (!iu) { 2194bb12588aSDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX 2195bb12588aSDavid Dillow "no IU available to send response\n"); 219676c75b25SBart Van Assche return 1; 2197bb12588aSDavid Dillow } 2198bb12588aSDavid Dillow 2199882981f4SBart Van Assche iu->num_sge = 1; 2200bb12588aSDavid Dillow ib_dma_sync_single_for_cpu(dev, iu->dma, len, DMA_TO_DEVICE); 2201bb12588aSDavid Dillow memcpy(iu->buf, rsp, len); 2202bb12588aSDavid Dillow ib_dma_sync_single_for_device(dev, iu->dma, len, DMA_TO_DEVICE); 2203bb12588aSDavid Dillow 2204509c07bcSBart Van Assche err = srp_post_send(ch, iu, len); 220576c75b25SBart Van Assche if (err) { 2206bb12588aSDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX 2207bb12588aSDavid Dillow "unable to post response: %d\n", err); 2208509c07bcSBart Van Assche srp_put_tx_iu(ch, iu, SRP_IU_RSP); 220976c75b25SBart Van Assche } 2210bb12588aSDavid Dillow 2211bb12588aSDavid Dillow return err; 2212bb12588aSDavid Dillow } 2213bb12588aSDavid Dillow 2214509c07bcSBart Van Assche static void srp_process_cred_req(struct srp_rdma_ch *ch, 2215bb12588aSDavid Dillow struct srp_cred_req *req) 2216bb12588aSDavid Dillow { 2217bb12588aSDavid Dillow struct srp_cred_rsp rsp = { 2218bb12588aSDavid Dillow .opcode = SRP_CRED_RSP, 2219bb12588aSDavid Dillow .tag = req->tag, 2220bb12588aSDavid Dillow }; 2221bb12588aSDavid Dillow s32 delta = be32_to_cpu(req->req_lim_delta); 2222bb12588aSDavid Dillow 2223509c07bcSBart Van Assche if (srp_response_common(ch, delta, &rsp, sizeof(rsp))) 2224509c07bcSBart Van Assche shost_printk(KERN_ERR, ch->target->scsi_host, PFX 2225bb12588aSDavid Dillow "problems processing SRP_CRED_REQ\n"); 2226bb12588aSDavid Dillow } 2227bb12588aSDavid Dillow 2228509c07bcSBart Van Assche static void srp_process_aer_req(struct srp_rdma_ch *ch, 2229bb12588aSDavid Dillow struct srp_aer_req *req) 2230bb12588aSDavid Dillow { 2231509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 2232bb12588aSDavid Dillow struct srp_aer_rsp rsp = { 2233bb12588aSDavid Dillow .opcode = SRP_AER_RSP, 2234bb12588aSDavid Dillow .tag = req->tag, 2235bb12588aSDavid Dillow }; 2236bb12588aSDavid Dillow s32 delta = be32_to_cpu(req->req_lim_delta); 2237bb12588aSDavid Dillow 2238bb12588aSDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX 2239985aa495SBart Van Assche "ignoring AER for LUN %llu\n", scsilun_to_int(&req->lun)); 2240bb12588aSDavid Dillow 2241509c07bcSBart Van Assche if (srp_response_common(ch, delta, &rsp, sizeof(rsp))) 2242bb12588aSDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX 2243bb12588aSDavid Dillow "problems processing SRP_AER_REQ\n"); 2244bb12588aSDavid Dillow } 2245bb12588aSDavid Dillow 22461dc7b1f1SChristoph Hellwig static void srp_recv_done(struct ib_cq *cq, struct ib_wc *wc) 2247aef9ec39SRoland Dreier { 22481dc7b1f1SChristoph Hellwig struct srp_iu *iu = container_of(wc->wr_cqe, struct srp_iu, cqe); 22491dc7b1f1SChristoph Hellwig struct srp_rdma_ch *ch = cq->cq_context; 2250509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 2251dcb4cb85SBart Van Assche struct ib_device *dev = target->srp_host->srp_dev->dev; 2252c996bb47SBart Van Assche int res; 2253aef9ec39SRoland Dreier u8 opcode; 2254aef9ec39SRoland Dreier 22551dc7b1f1SChristoph Hellwig if (unlikely(wc->status != IB_WC_SUCCESS)) { 22561dc7b1f1SChristoph Hellwig srp_handle_qp_err(cq, wc, "RECV"); 22571dc7b1f1SChristoph Hellwig return; 22581dc7b1f1SChristoph Hellwig } 22591dc7b1f1SChristoph Hellwig 2260509c07bcSBart Van Assche ib_dma_sync_single_for_cpu(dev, iu->dma, ch->max_ti_iu_len, 226185507bccSRalph Campbell DMA_FROM_DEVICE); 2262aef9ec39SRoland Dreier 2263aef9ec39SRoland Dreier opcode = *(u8 *) iu->buf; 2264aef9ec39SRoland Dreier 2265aef9ec39SRoland Dreier if (0) { 22667aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 22677aa54bd7SDavid Dillow PFX "recv completion, opcode 0x%02x\n", opcode); 22687a700811SBart Van Assche print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 8, 1, 22697a700811SBart Van Assche iu->buf, wc->byte_len, true); 2270aef9ec39SRoland Dreier } 2271aef9ec39SRoland Dreier 2272aef9ec39SRoland Dreier switch (opcode) { 2273aef9ec39SRoland Dreier case SRP_RSP: 2274509c07bcSBart Van Assche srp_process_rsp(ch, iu->buf); 2275aef9ec39SRoland Dreier break; 2276aef9ec39SRoland Dreier 2277bb12588aSDavid Dillow case SRP_CRED_REQ: 2278509c07bcSBart Van Assche srp_process_cred_req(ch, iu->buf); 2279bb12588aSDavid Dillow break; 2280bb12588aSDavid Dillow 2281bb12588aSDavid Dillow case SRP_AER_REQ: 2282509c07bcSBart Van Assche srp_process_aer_req(ch, iu->buf); 2283bb12588aSDavid Dillow break; 2284bb12588aSDavid Dillow 2285aef9ec39SRoland Dreier case SRP_T_LOGOUT: 2286aef9ec39SRoland Dreier /* XXX Handle target logout */ 22877aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 22887aa54bd7SDavid Dillow PFX "Got target logout request\n"); 2289aef9ec39SRoland Dreier break; 2290aef9ec39SRoland Dreier 2291aef9ec39SRoland Dreier default: 22927aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 22937aa54bd7SDavid Dillow PFX "Unhandled SRP opcode 0x%02x\n", opcode); 2294aef9ec39SRoland Dreier break; 2295aef9ec39SRoland Dreier } 2296aef9ec39SRoland Dreier 2297509c07bcSBart Van Assche ib_dma_sync_single_for_device(dev, iu->dma, ch->max_ti_iu_len, 229885507bccSRalph Campbell DMA_FROM_DEVICE); 2299c996bb47SBart Van Assche 2300509c07bcSBart Van Assche res = srp_post_recv(ch, iu); 2301c996bb47SBart Van Assche if (res != 0) 2302c996bb47SBart Van Assche shost_printk(KERN_ERR, target->scsi_host, 2303c996bb47SBart Van Assche PFX "Recv failed with error code %d\n", res); 2304aef9ec39SRoland Dreier } 2305aef9ec39SRoland Dreier 2306c1120f89SBart Van Assche /** 2307c1120f89SBart Van Assche * srp_tl_err_work() - handle a transport layer error 2308af24663bSBart Van Assche * @work: Work structure embedded in an SRP target port. 2309c1120f89SBart Van Assche * 2310c1120f89SBart Van Assche * Note: This function may get invoked before the rport has been created, 2311c1120f89SBart Van Assche * hence the target->rport test. 2312c1120f89SBart Van Assche */ 2313c1120f89SBart Van Assche static void srp_tl_err_work(struct work_struct *work) 2314c1120f89SBart Van Assche { 2315c1120f89SBart Van Assche struct srp_target_port *target; 2316c1120f89SBart Van Assche 2317c1120f89SBart Van Assche target = container_of(work, struct srp_target_port, tl_err_work); 2318c1120f89SBart Van Assche if (target->rport) 2319c1120f89SBart Van Assche srp_start_tl_fail_timers(target->rport); 2320c1120f89SBart Van Assche } 2321c1120f89SBart Van Assche 23221dc7b1f1SChristoph Hellwig static void srp_handle_qp_err(struct ib_cq *cq, struct ib_wc *wc, 23231dc7b1f1SChristoph Hellwig const char *opname) 2324948d1e88SBart Van Assche { 23251dc7b1f1SChristoph Hellwig struct srp_rdma_ch *ch = cq->cq_context; 23267dad6b2eSBart Van Assche struct srp_target_port *target = ch->target; 23277dad6b2eSBart Van Assche 2328c014c8cdSBart Van Assche if (ch->connected && !target->qp_in_error) { 23295cfb1782SBart Van Assche shost_printk(KERN_ERR, target->scsi_host, 23301dc7b1f1SChristoph Hellwig PFX "failed %s status %s (%d) for CQE %p\n", 23311dc7b1f1SChristoph Hellwig opname, ib_wc_status_msg(wc->status), wc->status, 23321dc7b1f1SChristoph Hellwig wc->wr_cqe); 2333c1120f89SBart Van Assche queue_work(system_long_wq, &target->tl_err_work); 23344f0af697SBart Van Assche } 2335948d1e88SBart Van Assche target->qp_in_error = true; 2336948d1e88SBart Van Assche } 2337948d1e88SBart Van Assche 233876c75b25SBart Van Assche static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd) 2339aef9ec39SRoland Dreier { 234076c75b25SBart Van Assche struct srp_target_port *target = host_to_target(shost); 2341a95cadb9SBart Van Assche struct srp_rport *rport = target->rport; 2342509c07bcSBart Van Assche struct srp_rdma_ch *ch; 2343aef9ec39SRoland Dreier struct srp_request *req; 2344aef9ec39SRoland Dreier struct srp_iu *iu; 2345aef9ec39SRoland Dreier struct srp_cmd *cmd; 234685507bccSRalph Campbell struct ib_device *dev; 234776c75b25SBart Van Assche unsigned long flags; 234877f2c1a4SBart Van Assche u32 tag; 234977f2c1a4SBart Van Assche u16 idx; 2350d1b4289eSBart Van Assche int len, ret; 2351a95cadb9SBart Van Assche const bool in_scsi_eh = !in_interrupt() && current == shost->ehandler; 2352a95cadb9SBart Van Assche 2353a95cadb9SBart Van Assche /* 2354a95cadb9SBart Van Assche * The SCSI EH thread is the only context from which srp_queuecommand() 2355a95cadb9SBart Van Assche * can get invoked for blocked devices (SDEV_BLOCK / 2356a95cadb9SBart Van Assche * SDEV_CREATED_BLOCK). Avoid racing with srp_reconnect_rport() by 2357a95cadb9SBart Van Assche * locking the rport mutex if invoked from inside the SCSI EH. 2358a95cadb9SBart Van Assche */ 2359a95cadb9SBart Van Assche if (in_scsi_eh) 2360a95cadb9SBart Van Assche mutex_lock(&rport->mutex); 2361aef9ec39SRoland Dreier 2362d1b4289eSBart Van Assche scmnd->result = srp_chkready(target->rport); 2363d1b4289eSBart Van Assche if (unlikely(scmnd->result)) 2364d1b4289eSBart Van Assche goto err; 23652ce19e72SBart Van Assche 236677f2c1a4SBart Van Assche WARN_ON_ONCE(scmnd->request->tag < 0); 236777f2c1a4SBart Van Assche tag = blk_mq_unique_tag(scmnd->request); 2368d92c0da7SBart Van Assche ch = &target->ch[blk_mq_unique_tag_to_hwq(tag)]; 236977f2c1a4SBart Van Assche idx = blk_mq_unique_tag_to_tag(tag); 237077f2c1a4SBart Van Assche WARN_ONCE(idx >= target->req_ring_size, "%s: tag %#x: idx %d >= %d\n", 237177f2c1a4SBart Van Assche dev_name(&shost->shost_gendev), tag, idx, 237277f2c1a4SBart Van Assche target->req_ring_size); 2373509c07bcSBart Van Assche 2374509c07bcSBart Van Assche spin_lock_irqsave(&ch->lock, flags); 2375509c07bcSBart Van Assche iu = __srp_get_tx_iu(ch, SRP_IU_CMD); 2376509c07bcSBart Van Assche spin_unlock_irqrestore(&ch->lock, flags); 2377aef9ec39SRoland Dreier 237877f2c1a4SBart Van Assche if (!iu) 237977f2c1a4SBart Van Assche goto err; 238077f2c1a4SBart Van Assche 238177f2c1a4SBart Van Assche req = &ch->req_ring[idx]; 238205321937SGreg Kroah-Hartman dev = target->srp_host->srp_dev->dev; 2383513d5647SBart Van Assche ib_dma_sync_single_for_cpu(dev, iu->dma, ch->max_it_iu_len, 238485507bccSRalph Campbell DMA_TO_DEVICE); 2385aef9ec39SRoland Dreier 2386f8b6e31eSDavid Dillow scmnd->host_scribble = (void *) req; 2387aef9ec39SRoland Dreier 2388aef9ec39SRoland Dreier cmd = iu->buf; 2389aef9ec39SRoland Dreier memset(cmd, 0, sizeof *cmd); 2390aef9ec39SRoland Dreier 2391aef9ec39SRoland Dreier cmd->opcode = SRP_CMD; 2392985aa495SBart Van Assche int_to_scsilun(scmnd->device->lun, &cmd->lun); 239377f2c1a4SBart Van Assche cmd->tag = tag; 2394aef9ec39SRoland Dreier memcpy(cmd->cdb, scmnd->cmnd, scmnd->cmd_len); 2395482fffc4SBart Van Assche if (unlikely(scmnd->cmd_len > sizeof(cmd->cdb))) { 2396482fffc4SBart Van Assche cmd->add_cdb_len = round_up(scmnd->cmd_len - sizeof(cmd->cdb), 2397482fffc4SBart Van Assche 4); 2398482fffc4SBart Van Assche if (WARN_ON_ONCE(cmd->add_cdb_len > SRP_MAX_ADD_CDB_LEN)) 2399482fffc4SBart Van Assche goto err_iu; 2400482fffc4SBart Van Assche } 2401aef9ec39SRoland Dreier 2402aef9ec39SRoland Dreier req->scmnd = scmnd; 2403aef9ec39SRoland Dreier req->cmd = iu; 2404aef9ec39SRoland Dreier 2405509c07bcSBart Van Assche len = srp_map_data(scmnd, ch, req); 2406aef9ec39SRoland Dreier if (len < 0) { 24077aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 2408d1b4289eSBart Van Assche PFX "Failed to map data (%d)\n", len); 2409d1b4289eSBart Van Assche /* 2410d1b4289eSBart Van Assche * If we ran out of memory descriptors (-ENOMEM) because an 2411d1b4289eSBart Van Assche * application is queuing many requests with more than 241252ede08fSBart Van Assche * max_pages_per_mr sg-list elements, tell the SCSI mid-layer 2413d1b4289eSBart Van Assche * to reduce queue depth temporarily. 2414d1b4289eSBart Van Assche */ 2415d1b4289eSBart Van Assche scmnd->result = len == -ENOMEM ? 2416d1b4289eSBart Van Assche DID_OK << 16 | QUEUE_FULL << 1 : DID_ERROR << 16; 241776c75b25SBart Van Assche goto err_iu; 2418aef9ec39SRoland Dreier } 2419aef9ec39SRoland Dreier 2420513d5647SBart Van Assche ib_dma_sync_single_for_device(dev, iu->dma, ch->max_it_iu_len, 242185507bccSRalph Campbell DMA_TO_DEVICE); 2422aef9ec39SRoland Dreier 2423509c07bcSBart Van Assche if (srp_post_send(ch, iu, len)) { 24247aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX "Send failed\n"); 24252ee00f6aSBart Van Assche scmnd->result = DID_ERROR << 16; 2426aef9ec39SRoland Dreier goto err_unmap; 2427aef9ec39SRoland Dreier } 2428aef9ec39SRoland Dreier 2429d1b4289eSBart Van Assche ret = 0; 2430d1b4289eSBart Van Assche 2431a95cadb9SBart Van Assche unlock_rport: 2432a95cadb9SBart Van Assche if (in_scsi_eh) 2433a95cadb9SBart Van Assche mutex_unlock(&rport->mutex); 2434a95cadb9SBart Van Assche 2435d1b4289eSBart Van Assche return ret; 2436aef9ec39SRoland Dreier 2437aef9ec39SRoland Dreier err_unmap: 2438509c07bcSBart Van Assche srp_unmap_data(scmnd, ch, req); 2439aef9ec39SRoland Dreier 244076c75b25SBart Van Assche err_iu: 2441509c07bcSBart Van Assche srp_put_tx_iu(ch, iu, SRP_IU_CMD); 244276c75b25SBart Van Assche 2443024ca901SBart Van Assche /* 2444024ca901SBart Van Assche * Avoid that the loops that iterate over the request ring can 2445024ca901SBart Van Assche * encounter a dangling SCSI command pointer. 2446024ca901SBart Van Assche */ 2447024ca901SBart Van Assche req->scmnd = NULL; 2448024ca901SBart Van Assche 2449d1b4289eSBart Van Assche err: 2450d1b4289eSBart Van Assche if (scmnd->result) { 2451d1b4289eSBart Van Assche scmnd->scsi_done(scmnd); 2452d1b4289eSBart Van Assche ret = 0; 2453d1b4289eSBart Van Assche } else { 2454d1b4289eSBart Van Assche ret = SCSI_MLQUEUE_HOST_BUSY; 2455d1b4289eSBart Van Assche } 2456a95cadb9SBart Van Assche 2457d1b4289eSBart Van Assche goto unlock_rport; 2458aef9ec39SRoland Dreier } 2459aef9ec39SRoland Dreier 24604d73f95fSBart Van Assche /* 24614d73f95fSBart Van Assche * Note: the resources allocated in this function are freed in 2462509c07bcSBart Van Assche * srp_free_ch_ib(). 24634d73f95fSBart Van Assche */ 2464509c07bcSBart Van Assche static int srp_alloc_iu_bufs(struct srp_rdma_ch *ch) 2465aef9ec39SRoland Dreier { 2466509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 2467aef9ec39SRoland Dreier int i; 2468aef9ec39SRoland Dreier 2469509c07bcSBart Van Assche ch->rx_ring = kcalloc(target->queue_size, sizeof(*ch->rx_ring), 24704d73f95fSBart Van Assche GFP_KERNEL); 2471509c07bcSBart Van Assche if (!ch->rx_ring) 24724d73f95fSBart Van Assche goto err_no_ring; 2473509c07bcSBart Van Assche ch->tx_ring = kcalloc(target->queue_size, sizeof(*ch->tx_ring), 24744d73f95fSBart Van Assche GFP_KERNEL); 2475509c07bcSBart Van Assche if (!ch->tx_ring) 24764d73f95fSBart Van Assche goto err_no_ring; 24774d73f95fSBart Van Assche 24784d73f95fSBart Van Assche for (i = 0; i < target->queue_size; ++i) { 2479509c07bcSBart Van Assche ch->rx_ring[i] = srp_alloc_iu(target->srp_host, 2480509c07bcSBart Van Assche ch->max_ti_iu_len, 2481aef9ec39SRoland Dreier GFP_KERNEL, DMA_FROM_DEVICE); 2482509c07bcSBart Van Assche if (!ch->rx_ring[i]) 2483aef9ec39SRoland Dreier goto err; 2484aef9ec39SRoland Dreier } 2485aef9ec39SRoland Dreier 24864d73f95fSBart Van Assche for (i = 0; i < target->queue_size; ++i) { 2487509c07bcSBart Van Assche ch->tx_ring[i] = srp_alloc_iu(target->srp_host, 2488513d5647SBart Van Assche ch->max_it_iu_len, 2489aef9ec39SRoland Dreier GFP_KERNEL, DMA_TO_DEVICE); 2490509c07bcSBart Van Assche if (!ch->tx_ring[i]) 2491aef9ec39SRoland Dreier goto err; 2492dcb4cb85SBart Van Assche 2493509c07bcSBart Van Assche list_add(&ch->tx_ring[i]->list, &ch->free_tx); 2494aef9ec39SRoland Dreier } 2495aef9ec39SRoland Dreier 2496aef9ec39SRoland Dreier return 0; 2497aef9ec39SRoland Dreier 2498aef9ec39SRoland Dreier err: 24994d73f95fSBart Van Assche for (i = 0; i < target->queue_size; ++i) { 2500509c07bcSBart Van Assche srp_free_iu(target->srp_host, ch->rx_ring[i]); 2501509c07bcSBart Van Assche srp_free_iu(target->srp_host, ch->tx_ring[i]); 2502aef9ec39SRoland Dreier } 2503aef9ec39SRoland Dreier 25044d73f95fSBart Van Assche 25054d73f95fSBart Van Assche err_no_ring: 2506509c07bcSBart Van Assche kfree(ch->tx_ring); 2507509c07bcSBart Van Assche ch->tx_ring = NULL; 2508509c07bcSBart Van Assche kfree(ch->rx_ring); 2509509c07bcSBart Van Assche ch->rx_ring = NULL; 2510aef9ec39SRoland Dreier 2511aef9ec39SRoland Dreier return -ENOMEM; 2512aef9ec39SRoland Dreier } 2513aef9ec39SRoland Dreier 2514c9b03c1aSBart Van Assche static uint32_t srp_compute_rq_tmo(struct ib_qp_attr *qp_attr, int attr_mask) 2515c9b03c1aSBart Van Assche { 2516c9b03c1aSBart Van Assche uint64_t T_tr_ns, max_compl_time_ms; 2517c9b03c1aSBart Van Assche uint32_t rq_tmo_jiffies; 2518c9b03c1aSBart Van Assche 2519c9b03c1aSBart Van Assche /* 2520c9b03c1aSBart Van Assche * According to section 11.2.4.2 in the IBTA spec (Modify Queue Pair, 2521c9b03c1aSBart Van Assche * table 91), both the QP timeout and the retry count have to be set 2522c9b03c1aSBart Van Assche * for RC QP's during the RTR to RTS transition. 2523c9b03c1aSBart Van Assche */ 2524c9b03c1aSBart Van Assche WARN_ON_ONCE((attr_mask & (IB_QP_TIMEOUT | IB_QP_RETRY_CNT)) != 2525c9b03c1aSBart Van Assche (IB_QP_TIMEOUT | IB_QP_RETRY_CNT)); 2526c9b03c1aSBart Van Assche 2527c9b03c1aSBart Van Assche /* 2528c9b03c1aSBart Van Assche * Set target->rq_tmo_jiffies to one second more than the largest time 2529c9b03c1aSBart Van Assche * it can take before an error completion is generated. See also 2530c9b03c1aSBart Van Assche * C9-140..142 in the IBTA spec for more information about how to 2531c9b03c1aSBart Van Assche * convert the QP Local ACK Timeout value to nanoseconds. 2532c9b03c1aSBart Van Assche */ 2533c9b03c1aSBart Van Assche T_tr_ns = 4096 * (1ULL << qp_attr->timeout); 2534c9b03c1aSBart Van Assche max_compl_time_ms = qp_attr->retry_cnt * 4 * T_tr_ns; 2535c9b03c1aSBart Van Assche do_div(max_compl_time_ms, NSEC_PER_MSEC); 2536c9b03c1aSBart Van Assche rq_tmo_jiffies = msecs_to_jiffies(max_compl_time_ms + 1000); 2537c9b03c1aSBart Van Assche 2538c9b03c1aSBart Van Assche return rq_tmo_jiffies; 2539c9b03c1aSBart Van Assche } 2540c9b03c1aSBart Van Assche 2541961e0be8SDavid Dillow static void srp_cm_rep_handler(struct ib_cm_id *cm_id, 2542e6300cbdSBart Van Assche const struct srp_login_rsp *lrsp, 2543509c07bcSBart Van Assche struct srp_rdma_ch *ch) 2544961e0be8SDavid Dillow { 2545509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 2546961e0be8SDavid Dillow struct ib_qp_attr *qp_attr = NULL; 2547961e0be8SDavid Dillow int attr_mask = 0; 254819f31343SBart Van Assche int ret = 0; 2549961e0be8SDavid Dillow int i; 2550961e0be8SDavid Dillow 2551961e0be8SDavid Dillow if (lrsp->opcode == SRP_LOGIN_RSP) { 2552509c07bcSBart Van Assche ch->max_ti_iu_len = be32_to_cpu(lrsp->max_ti_iu_len); 2553509c07bcSBart Van Assche ch->req_lim = be32_to_cpu(lrsp->req_lim_delta); 2554882981f4SBart Van Assche ch->use_imm_data = lrsp->rsp_flags & SRP_LOGIN_RSP_IMMED_SUPP; 2555882981f4SBart Van Assche ch->max_it_iu_len = srp_max_it_iu_len(target->cmd_sg_cnt, 2556882981f4SBart Van Assche ch->use_imm_data); 2557513d5647SBart Van Assche WARN_ON_ONCE(ch->max_it_iu_len > 2558513d5647SBart Van Assche be32_to_cpu(lrsp->max_it_iu_len)); 2559961e0be8SDavid Dillow 2560882981f4SBart Van Assche if (ch->use_imm_data) 2561882981f4SBart Van Assche shost_printk(KERN_DEBUG, target->scsi_host, 2562882981f4SBart Van Assche PFX "using immediate data\n"); 2563961e0be8SDavid Dillow 2564961e0be8SDavid Dillow /* 2565961e0be8SDavid Dillow * Reserve credits for task management so we don't 2566961e0be8SDavid Dillow * bounce requests back to the SCSI mid-layer. 2567961e0be8SDavid Dillow */ 2568961e0be8SDavid Dillow target->scsi_host->can_queue 2569509c07bcSBart Van Assche = min(ch->req_lim - SRP_TSK_MGMT_SQ_SIZE, 2570961e0be8SDavid Dillow target->scsi_host->can_queue); 25714d73f95fSBart Van Assche target->scsi_host->cmd_per_lun 25724d73f95fSBart Van Assche = min_t(int, target->scsi_host->can_queue, 25734d73f95fSBart Van Assche target->scsi_host->cmd_per_lun); 2574961e0be8SDavid Dillow } else { 2575961e0be8SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 2576961e0be8SDavid Dillow PFX "Unhandled RSP opcode %#x\n", lrsp->opcode); 2577961e0be8SDavid Dillow ret = -ECONNRESET; 2578961e0be8SDavid Dillow goto error; 2579961e0be8SDavid Dillow } 2580961e0be8SDavid Dillow 2581509c07bcSBart Van Assche if (!ch->rx_ring) { 2582509c07bcSBart Van Assche ret = srp_alloc_iu_bufs(ch); 2583961e0be8SDavid Dillow if (ret) 2584961e0be8SDavid Dillow goto error; 2585961e0be8SDavid Dillow } 2586961e0be8SDavid Dillow 258719f31343SBart Van Assche for (i = 0; i < target->queue_size; i++) { 258819f31343SBart Van Assche struct srp_iu *iu = ch->rx_ring[i]; 258919f31343SBart Van Assche 259019f31343SBart Van Assche ret = srp_post_recv(ch, iu); 259119f31343SBart Van Assche if (ret) 259219f31343SBart Van Assche goto error; 259319f31343SBart Van Assche } 259419f31343SBart Van Assche 259519f31343SBart Van Assche if (!target->using_rdma_cm) { 2596961e0be8SDavid Dillow ret = -ENOMEM; 259719f31343SBart Van Assche qp_attr = kmalloc(sizeof(*qp_attr), GFP_KERNEL); 2598961e0be8SDavid Dillow if (!qp_attr) 2599961e0be8SDavid Dillow goto error; 2600961e0be8SDavid Dillow 2601961e0be8SDavid Dillow qp_attr->qp_state = IB_QPS_RTR; 2602961e0be8SDavid Dillow ret = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask); 2603961e0be8SDavid Dillow if (ret) 2604961e0be8SDavid Dillow goto error_free; 2605961e0be8SDavid Dillow 2606509c07bcSBart Van Assche ret = ib_modify_qp(ch->qp, qp_attr, attr_mask); 2607961e0be8SDavid Dillow if (ret) 2608961e0be8SDavid Dillow goto error_free; 2609961e0be8SDavid Dillow 2610961e0be8SDavid Dillow qp_attr->qp_state = IB_QPS_RTS; 2611961e0be8SDavid Dillow ret = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask); 2612961e0be8SDavid Dillow if (ret) 2613961e0be8SDavid Dillow goto error_free; 2614961e0be8SDavid Dillow 2615c9b03c1aSBart Van Assche target->rq_tmo_jiffies = srp_compute_rq_tmo(qp_attr, attr_mask); 2616c9b03c1aSBart Van Assche 2617509c07bcSBart Van Assche ret = ib_modify_qp(ch->qp, qp_attr, attr_mask); 2618961e0be8SDavid Dillow if (ret) 2619961e0be8SDavid Dillow goto error_free; 2620961e0be8SDavid Dillow 2621961e0be8SDavid Dillow ret = ib_send_cm_rtu(cm_id, NULL, 0); 262219f31343SBart Van Assche } 2623961e0be8SDavid Dillow 2624961e0be8SDavid Dillow error_free: 2625961e0be8SDavid Dillow kfree(qp_attr); 2626961e0be8SDavid Dillow 2627961e0be8SDavid Dillow error: 2628509c07bcSBart Van Assche ch->status = ret; 2629961e0be8SDavid Dillow } 2630961e0be8SDavid Dillow 263119f31343SBart Van Assche static void srp_ib_cm_rej_handler(struct ib_cm_id *cm_id, 2632e7ff98aeSParav Pandit const struct ib_cm_event *event, 2633509c07bcSBart Van Assche struct srp_rdma_ch *ch) 2634aef9ec39SRoland Dreier { 2635509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 26367aa54bd7SDavid Dillow struct Scsi_Host *shost = target->scsi_host; 2637aef9ec39SRoland Dreier struct ib_class_port_info *cpi; 2638aef9ec39SRoland Dreier int opcode; 263919f31343SBart Van Assche u16 dlid; 2640aef9ec39SRoland Dreier 2641aef9ec39SRoland Dreier switch (event->param.rej_rcvd.reason) { 2642aef9ec39SRoland Dreier case IB_CM_REJ_PORT_CM_REDIRECT: 2643aef9ec39SRoland Dreier cpi = event->param.rej_rcvd.ari; 264419f31343SBart Van Assche dlid = be16_to_cpu(cpi->redirect_lid); 264519f31343SBart Van Assche sa_path_set_dlid(&ch->ib_cm.path, dlid); 264619f31343SBart Van Assche ch->ib_cm.path.pkey = cpi->redirect_pkey; 2647aef9ec39SRoland Dreier cm_id->remote_cm_qpn = be32_to_cpu(cpi->redirect_qp) & 0x00ffffff; 264819f31343SBart Van Assche memcpy(ch->ib_cm.path.dgid.raw, cpi->redirect_gid, 16); 2649aef9ec39SRoland Dreier 265019f31343SBart Van Assche ch->status = dlid ? SRP_DLID_REDIRECT : SRP_PORT_REDIRECT; 2651aef9ec39SRoland Dreier break; 2652aef9ec39SRoland Dreier 2653aef9ec39SRoland Dreier case IB_CM_REJ_PORT_REDIRECT: 26545d7cbfd6SRoland Dreier if (srp_target_is_topspin(target)) { 265519f31343SBart Van Assche union ib_gid *dgid = &ch->ib_cm.path.dgid; 265619f31343SBart Van Assche 2657aef9ec39SRoland Dreier /* 2658aef9ec39SRoland Dreier * Topspin/Cisco SRP gateways incorrectly send 2659aef9ec39SRoland Dreier * reject reason code 25 when they mean 24 2660aef9ec39SRoland Dreier * (port redirect). 2661aef9ec39SRoland Dreier */ 266219f31343SBart Van Assche memcpy(dgid->raw, event->param.rej_rcvd.ari, 16); 2663aef9ec39SRoland Dreier 26647aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, shost, 26657aa54bd7SDavid Dillow PFX "Topspin/Cisco redirect to target port GID %016llx%016llx\n", 266619f31343SBart Van Assche be64_to_cpu(dgid->global.subnet_prefix), 266719f31343SBart Van Assche be64_to_cpu(dgid->global.interface_id)); 2668aef9ec39SRoland Dreier 2669509c07bcSBart Van Assche ch->status = SRP_PORT_REDIRECT; 2670aef9ec39SRoland Dreier } else { 26717aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, 26727aa54bd7SDavid Dillow " REJ reason: IB_CM_REJ_PORT_REDIRECT\n"); 2673509c07bcSBart Van Assche ch->status = -ECONNRESET; 2674aef9ec39SRoland Dreier } 2675aef9ec39SRoland Dreier break; 2676aef9ec39SRoland Dreier 2677aef9ec39SRoland Dreier case IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID: 26787aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, 26797aa54bd7SDavid Dillow " REJ reason: IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID\n"); 2680509c07bcSBart Van Assche ch->status = -ECONNRESET; 2681aef9ec39SRoland Dreier break; 2682aef9ec39SRoland Dreier 2683aef9ec39SRoland Dreier case IB_CM_REJ_CONSUMER_DEFINED: 2684aef9ec39SRoland Dreier opcode = *(u8 *) event->private_data; 2685aef9ec39SRoland Dreier if (opcode == SRP_LOGIN_REJ) { 2686aef9ec39SRoland Dreier struct srp_login_rej *rej = event->private_data; 2687aef9ec39SRoland Dreier u32 reason = be32_to_cpu(rej->reason); 2688aef9ec39SRoland Dreier 2689aef9ec39SRoland Dreier if (reason == SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE) 26907aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, 26917aa54bd7SDavid Dillow PFX "SRP_LOGIN_REJ: requested max_it_iu_len too large\n"); 2692aef9ec39SRoland Dreier else 2693e7ffde01SBart Van Assche shost_printk(KERN_WARNING, shost, PFX 2694e7ffde01SBart Van Assche "SRP LOGIN from %pI6 to %pI6 REJECTED, reason 0x%08x\n", 2695747fe000SBart Van Assche target->sgid.raw, 269619f31343SBart Van Assche target->ib_cm.orig_dgid.raw, 269719f31343SBart Van Assche reason); 2698aef9ec39SRoland Dreier } else 26997aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, 27007aa54bd7SDavid Dillow " REJ reason: IB_CM_REJ_CONSUMER_DEFINED," 2701aef9ec39SRoland Dreier " opcode 0x%02x\n", opcode); 2702509c07bcSBart Van Assche ch->status = -ECONNRESET; 2703aef9ec39SRoland Dreier break; 2704aef9ec39SRoland Dreier 27059fe4bcf4SDavid Dillow case IB_CM_REJ_STALE_CONN: 27069fe4bcf4SDavid Dillow shost_printk(KERN_WARNING, shost, " REJ reason: stale connection\n"); 2707509c07bcSBart Van Assche ch->status = SRP_STALE_CONN; 27089fe4bcf4SDavid Dillow break; 27099fe4bcf4SDavid Dillow 2710aef9ec39SRoland Dreier default: 27117aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, " REJ reason 0x%x\n", 2712aef9ec39SRoland Dreier event->param.rej_rcvd.reason); 2713509c07bcSBart Van Assche ch->status = -ECONNRESET; 2714aef9ec39SRoland Dreier } 2715aef9ec39SRoland Dreier } 2716aef9ec39SRoland Dreier 2717e7ff98aeSParav Pandit static int srp_ib_cm_handler(struct ib_cm_id *cm_id, 2718e7ff98aeSParav Pandit const struct ib_cm_event *event) 2719aef9ec39SRoland Dreier { 2720509c07bcSBart Van Assche struct srp_rdma_ch *ch = cm_id->context; 2721509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 2722aef9ec39SRoland Dreier int comp = 0; 2723aef9ec39SRoland Dreier 2724aef9ec39SRoland Dreier switch (event->event) { 2725aef9ec39SRoland Dreier case IB_CM_REQ_ERROR: 27267aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, target->scsi_host, 27277aa54bd7SDavid Dillow PFX "Sending CM REQ failed\n"); 2728aef9ec39SRoland Dreier comp = 1; 2729509c07bcSBart Van Assche ch->status = -ECONNRESET; 2730aef9ec39SRoland Dreier break; 2731aef9ec39SRoland Dreier 2732aef9ec39SRoland Dreier case IB_CM_REP_RECEIVED: 2733aef9ec39SRoland Dreier comp = 1; 2734509c07bcSBart Van Assche srp_cm_rep_handler(cm_id, event->private_data, ch); 2735aef9ec39SRoland Dreier break; 2736aef9ec39SRoland Dreier 2737aef9ec39SRoland Dreier case IB_CM_REJ_RECEIVED: 27387aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, target->scsi_host, PFX "REJ received\n"); 2739aef9ec39SRoland Dreier comp = 1; 2740aef9ec39SRoland Dreier 274119f31343SBart Van Assche srp_ib_cm_rej_handler(cm_id, event, ch); 2742aef9ec39SRoland Dreier break; 2743aef9ec39SRoland Dreier 2744b7ac4ab4SIshai Rabinovitz case IB_CM_DREQ_RECEIVED: 27457aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 27467aa54bd7SDavid Dillow PFX "DREQ received - connection closed\n"); 2747c014c8cdSBart Van Assche ch->connected = false; 2748b7ac4ab4SIshai Rabinovitz if (ib_send_cm_drep(cm_id, NULL, 0)) 27497aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 27507aa54bd7SDavid Dillow PFX "Sending CM DREP failed\n"); 2751c1120f89SBart Van Assche queue_work(system_long_wq, &target->tl_err_work); 2752aef9ec39SRoland Dreier break; 2753aef9ec39SRoland Dreier 2754aef9ec39SRoland Dreier case IB_CM_TIMEWAIT_EXIT: 27557aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 27567aa54bd7SDavid Dillow PFX "connection closed\n"); 2757ac72d766SBart Van Assche comp = 1; 2758aef9ec39SRoland Dreier 2759509c07bcSBart Van Assche ch->status = 0; 2760aef9ec39SRoland Dreier break; 2761aef9ec39SRoland Dreier 2762b7ac4ab4SIshai Rabinovitz case IB_CM_MRA_RECEIVED: 2763b7ac4ab4SIshai Rabinovitz case IB_CM_DREQ_ERROR: 2764b7ac4ab4SIshai Rabinovitz case IB_CM_DREP_RECEIVED: 2765b7ac4ab4SIshai Rabinovitz break; 2766b7ac4ab4SIshai Rabinovitz 2767aef9ec39SRoland Dreier default: 27687aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 27697aa54bd7SDavid Dillow PFX "Unhandled CM event %d\n", event->event); 2770aef9ec39SRoland Dreier break; 2771aef9ec39SRoland Dreier } 2772aef9ec39SRoland Dreier 2773aef9ec39SRoland Dreier if (comp) 2774509c07bcSBart Van Assche complete(&ch->done); 2775aef9ec39SRoland Dreier 2776aef9ec39SRoland Dreier return 0; 2777aef9ec39SRoland Dreier } 2778aef9ec39SRoland Dreier 277919f31343SBart Van Assche static void srp_rdma_cm_rej_handler(struct srp_rdma_ch *ch, 278019f31343SBart Van Assche struct rdma_cm_event *event) 278119f31343SBart Van Assche { 278219f31343SBart Van Assche struct srp_target_port *target = ch->target; 278319f31343SBart Van Assche struct Scsi_Host *shost = target->scsi_host; 278419f31343SBart Van Assche int opcode; 278519f31343SBart Van Assche 278619f31343SBart Van Assche switch (event->status) { 278719f31343SBart Van Assche case IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID: 278819f31343SBart Van Assche shost_printk(KERN_WARNING, shost, 278919f31343SBart Van Assche " REJ reason: IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID\n"); 279019f31343SBart Van Assche ch->status = -ECONNRESET; 279119f31343SBart Van Assche break; 279219f31343SBart Van Assche 279319f31343SBart Van Assche case IB_CM_REJ_CONSUMER_DEFINED: 279419f31343SBart Van Assche opcode = *(u8 *) event->param.conn.private_data; 279519f31343SBart Van Assche if (opcode == SRP_LOGIN_REJ) { 279619f31343SBart Van Assche struct srp_login_rej *rej = 279719f31343SBart Van Assche (struct srp_login_rej *) 279819f31343SBart Van Assche event->param.conn.private_data; 279919f31343SBart Van Assche u32 reason = be32_to_cpu(rej->reason); 280019f31343SBart Van Assche 280119f31343SBart Van Assche if (reason == SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE) 280219f31343SBart Van Assche shost_printk(KERN_WARNING, shost, 280319f31343SBart Van Assche PFX "SRP_LOGIN_REJ: requested max_it_iu_len too large\n"); 280419f31343SBart Van Assche else 280519f31343SBart Van Assche shost_printk(KERN_WARNING, shost, 280619f31343SBart Van Assche PFX "SRP LOGIN REJECTED, reason 0x%08x\n", reason); 280719f31343SBart Van Assche } else { 280819f31343SBart Van Assche shost_printk(KERN_WARNING, shost, 280919f31343SBart Van Assche " REJ reason: IB_CM_REJ_CONSUMER_DEFINED, opcode 0x%02x\n", 281019f31343SBart Van Assche opcode); 281119f31343SBart Van Assche } 281219f31343SBart Van Assche ch->status = -ECONNRESET; 281319f31343SBart Van Assche break; 281419f31343SBart Van Assche 281519f31343SBart Van Assche case IB_CM_REJ_STALE_CONN: 281619f31343SBart Van Assche shost_printk(KERN_WARNING, shost, 281719f31343SBart Van Assche " REJ reason: stale connection\n"); 281819f31343SBart Van Assche ch->status = SRP_STALE_CONN; 281919f31343SBart Van Assche break; 282019f31343SBart Van Assche 282119f31343SBart Van Assche default: 282219f31343SBart Van Assche shost_printk(KERN_WARNING, shost, " REJ reason 0x%x\n", 282319f31343SBart Van Assche event->status); 282419f31343SBart Van Assche ch->status = -ECONNRESET; 282519f31343SBart Van Assche break; 282619f31343SBart Van Assche } 282719f31343SBart Van Assche } 282819f31343SBart Van Assche 282919f31343SBart Van Assche static int srp_rdma_cm_handler(struct rdma_cm_id *cm_id, 283019f31343SBart Van Assche struct rdma_cm_event *event) 283119f31343SBart Van Assche { 283219f31343SBart Van Assche struct srp_rdma_ch *ch = cm_id->context; 283319f31343SBart Van Assche struct srp_target_port *target = ch->target; 283419f31343SBart Van Assche int comp = 0; 283519f31343SBart Van Assche 283619f31343SBart Van Assche switch (event->event) { 283719f31343SBart Van Assche case RDMA_CM_EVENT_ADDR_RESOLVED: 283819f31343SBart Van Assche ch->status = 0; 283919f31343SBart Van Assche comp = 1; 284019f31343SBart Van Assche break; 284119f31343SBart Van Assche 284219f31343SBart Van Assche case RDMA_CM_EVENT_ADDR_ERROR: 284319f31343SBart Van Assche ch->status = -ENXIO; 284419f31343SBart Van Assche comp = 1; 284519f31343SBart Van Assche break; 284619f31343SBart Van Assche 284719f31343SBart Van Assche case RDMA_CM_EVENT_ROUTE_RESOLVED: 284819f31343SBart Van Assche ch->status = 0; 284919f31343SBart Van Assche comp = 1; 285019f31343SBart Van Assche break; 285119f31343SBart Van Assche 285219f31343SBart Van Assche case RDMA_CM_EVENT_ROUTE_ERROR: 285319f31343SBart Van Assche case RDMA_CM_EVENT_UNREACHABLE: 285419f31343SBart Van Assche ch->status = -EHOSTUNREACH; 285519f31343SBart Van Assche comp = 1; 285619f31343SBart Van Assche break; 285719f31343SBart Van Assche 285819f31343SBart Van Assche case RDMA_CM_EVENT_CONNECT_ERROR: 285919f31343SBart Van Assche shost_printk(KERN_DEBUG, target->scsi_host, 286019f31343SBart Van Assche PFX "Sending CM REQ failed\n"); 286119f31343SBart Van Assche comp = 1; 286219f31343SBart Van Assche ch->status = -ECONNRESET; 286319f31343SBart Van Assche break; 286419f31343SBart Van Assche 286519f31343SBart Van Assche case RDMA_CM_EVENT_ESTABLISHED: 286619f31343SBart Van Assche comp = 1; 286719f31343SBart Van Assche srp_cm_rep_handler(NULL, event->param.conn.private_data, ch); 286819f31343SBart Van Assche break; 286919f31343SBart Van Assche 287019f31343SBart Van Assche case RDMA_CM_EVENT_REJECTED: 287119f31343SBart Van Assche shost_printk(KERN_DEBUG, target->scsi_host, PFX "REJ received\n"); 287219f31343SBart Van Assche comp = 1; 287319f31343SBart Van Assche 287419f31343SBart Van Assche srp_rdma_cm_rej_handler(ch, event); 287519f31343SBart Van Assche break; 287619f31343SBart Van Assche 287719f31343SBart Van Assche case RDMA_CM_EVENT_DISCONNECTED: 287819f31343SBart Van Assche if (ch->connected) { 287919f31343SBart Van Assche shost_printk(KERN_WARNING, target->scsi_host, 288019f31343SBart Van Assche PFX "received DREQ\n"); 288119f31343SBart Van Assche rdma_disconnect(ch->rdma_cm.cm_id); 288219f31343SBart Van Assche comp = 1; 288319f31343SBart Van Assche ch->status = 0; 288419f31343SBart Van Assche queue_work(system_long_wq, &target->tl_err_work); 288519f31343SBart Van Assche } 288619f31343SBart Van Assche break; 288719f31343SBart Van Assche 288819f31343SBart Van Assche case RDMA_CM_EVENT_TIMEWAIT_EXIT: 288919f31343SBart Van Assche shost_printk(KERN_ERR, target->scsi_host, 289019f31343SBart Van Assche PFX "connection closed\n"); 289119f31343SBart Van Assche 289219f31343SBart Van Assche comp = 1; 289319f31343SBart Van Assche ch->status = 0; 289419f31343SBart Van Assche break; 289519f31343SBart Van Assche 289619f31343SBart Van Assche default: 289719f31343SBart Van Assche shost_printk(KERN_WARNING, target->scsi_host, 289819f31343SBart Van Assche PFX "Unhandled CM event %d\n", event->event); 289919f31343SBart Van Assche break; 290019f31343SBart Van Assche } 290119f31343SBart Van Assche 290219f31343SBart Van Assche if (comp) 290319f31343SBart Van Assche complete(&ch->done); 290419f31343SBart Van Assche 290519f31343SBart Van Assche return 0; 290619f31343SBart Van Assche } 290719f31343SBart Van Assche 290871444b97SJack Wang /** 290971444b97SJack Wang * srp_change_queue_depth - setting device queue depth 291071444b97SJack Wang * @sdev: scsi device struct 291171444b97SJack Wang * @qdepth: requested queue depth 291271444b97SJack Wang * 291371444b97SJack Wang * Returns queue depth. 291471444b97SJack Wang */ 291571444b97SJack Wang static int 2916db5ed4dfSChristoph Hellwig srp_change_queue_depth(struct scsi_device *sdev, int qdepth) 291771444b97SJack Wang { 291871444b97SJack Wang if (!sdev->tagged_supported) 29191e6f2416SChristoph Hellwig qdepth = 1; 2920db5ed4dfSChristoph Hellwig return scsi_change_queue_depth(sdev, qdepth); 292171444b97SJack Wang } 292271444b97SJack Wang 2923985aa495SBart Van Assche static int srp_send_tsk_mgmt(struct srp_rdma_ch *ch, u64 req_tag, u64 lun, 29240a6fdbdeSBart Van Assche u8 func, u8 *status) 2925aef9ec39SRoland Dreier { 2926509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 2927a95cadb9SBart Van Assche struct srp_rport *rport = target->rport; 292819081f31SDavid Dillow struct ib_device *dev = target->srp_host->srp_dev->dev; 2929aef9ec39SRoland Dreier struct srp_iu *iu; 2930aef9ec39SRoland Dreier struct srp_tsk_mgmt *tsk_mgmt; 29310a6fdbdeSBart Van Assche int res; 2932aef9ec39SRoland Dreier 2933c014c8cdSBart Van Assche if (!ch->connected || target->qp_in_error) 29343780d1f0SBart Van Assche return -1; 29353780d1f0SBart Van Assche 2936a95cadb9SBart Van Assche /* 2937509c07bcSBart Van Assche * Lock the rport mutex to avoid that srp_create_ch_ib() is 2938a95cadb9SBart Van Assche * invoked while a task management function is being sent. 2939a95cadb9SBart Van Assche */ 2940a95cadb9SBart Van Assche mutex_lock(&rport->mutex); 2941509c07bcSBart Van Assche spin_lock_irq(&ch->lock); 2942509c07bcSBart Van Assche iu = __srp_get_tx_iu(ch, SRP_IU_TSK_MGMT); 2943509c07bcSBart Van Assche spin_unlock_irq(&ch->lock); 294476c75b25SBart Van Assche 2945a95cadb9SBart Van Assche if (!iu) { 2946a95cadb9SBart Van Assche mutex_unlock(&rport->mutex); 2947a95cadb9SBart Van Assche 294876c75b25SBart Van Assche return -1; 2949a95cadb9SBart Van Assche } 2950aef9ec39SRoland Dreier 2951882981f4SBart Van Assche iu->num_sge = 1; 2952882981f4SBart Van Assche 295319081f31SDavid Dillow ib_dma_sync_single_for_cpu(dev, iu->dma, sizeof *tsk_mgmt, 295419081f31SDavid Dillow DMA_TO_DEVICE); 2955aef9ec39SRoland Dreier tsk_mgmt = iu->buf; 2956aef9ec39SRoland Dreier memset(tsk_mgmt, 0, sizeof *tsk_mgmt); 2957aef9ec39SRoland Dreier 2958aef9ec39SRoland Dreier tsk_mgmt->opcode = SRP_TSK_MGMT; 2959985aa495SBart Van Assche int_to_scsilun(lun, &tsk_mgmt->lun); 2960aef9ec39SRoland Dreier tsk_mgmt->tsk_mgmt_func = func; 2961f8b6e31eSDavid Dillow tsk_mgmt->task_tag = req_tag; 2962aef9ec39SRoland Dreier 29630a6fdbdeSBart Van Assche spin_lock_irq(&ch->lock); 29640a6fdbdeSBart Van Assche ch->tsk_mgmt_tag = (ch->tsk_mgmt_tag + 1) | SRP_TAG_TSK_MGMT; 29650a6fdbdeSBart Van Assche tsk_mgmt->tag = ch->tsk_mgmt_tag; 29660a6fdbdeSBart Van Assche spin_unlock_irq(&ch->lock); 29670a6fdbdeSBart Van Assche 29680a6fdbdeSBart Van Assche init_completion(&ch->tsk_mgmt_done); 29690a6fdbdeSBart Van Assche 297019081f31SDavid Dillow ib_dma_sync_single_for_device(dev, iu->dma, sizeof *tsk_mgmt, 297119081f31SDavid Dillow DMA_TO_DEVICE); 2972509c07bcSBart Van Assche if (srp_post_send(ch, iu, sizeof(*tsk_mgmt))) { 2973509c07bcSBart Van Assche srp_put_tx_iu(ch, iu, SRP_IU_TSK_MGMT); 2974a95cadb9SBart Van Assche mutex_unlock(&rport->mutex); 2975a95cadb9SBart Van Assche 297676c75b25SBart Van Assche return -1; 297776c75b25SBart Van Assche } 29780a6fdbdeSBart Van Assche res = wait_for_completion_timeout(&ch->tsk_mgmt_done, 29790a6fdbdeSBart Van Assche msecs_to_jiffies(SRP_ABORT_TIMEOUT_MS)); 29800a6fdbdeSBart Van Assche if (res > 0 && status) 29810a6fdbdeSBart Van Assche *status = ch->tsk_mgmt_status; 2982a95cadb9SBart Van Assche mutex_unlock(&rport->mutex); 2983d945e1dfSRoland Dreier 29840a6fdbdeSBart Van Assche WARN_ON_ONCE(res < 0); 2985aef9ec39SRoland Dreier 29860a6fdbdeSBart Van Assche return res > 0 ? 0 : -1; 2987d945e1dfSRoland Dreier } 2988d945e1dfSRoland Dreier 2989aef9ec39SRoland Dreier static int srp_abort(struct scsi_cmnd *scmnd) 2990aef9ec39SRoland Dreier { 2991d945e1dfSRoland Dreier struct srp_target_port *target = host_to_target(scmnd->device->host); 2992f8b6e31eSDavid Dillow struct srp_request *req = (struct srp_request *) scmnd->host_scribble; 299377f2c1a4SBart Van Assche u32 tag; 2994d92c0da7SBart Van Assche u16 ch_idx; 2995509c07bcSBart Van Assche struct srp_rdma_ch *ch; 2996086f44f5SBart Van Assche int ret; 2997d945e1dfSRoland Dreier 29987aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n"); 2999aef9ec39SRoland Dreier 3000d92c0da7SBart Van Assche if (!req) 300199b6697aSBart Van Assche return SUCCESS; 300277f2c1a4SBart Van Assche tag = blk_mq_unique_tag(scmnd->request); 3003d92c0da7SBart Van Assche ch_idx = blk_mq_unique_tag_to_hwq(tag); 3004d92c0da7SBart Van Assche if (WARN_ON_ONCE(ch_idx >= target->ch_count)) 3005d92c0da7SBart Van Assche return SUCCESS; 3006d92c0da7SBart Van Assche ch = &target->ch[ch_idx]; 3007d92c0da7SBart Van Assche if (!srp_claim_req(ch, req, NULL, scmnd)) 3008d92c0da7SBart Van Assche return SUCCESS; 3009d92c0da7SBart Van Assche shost_printk(KERN_ERR, target->scsi_host, 3010d92c0da7SBart Van Assche "Sending SRP abort for tag %#x\n", tag); 301177f2c1a4SBart Van Assche if (srp_send_tsk_mgmt(ch, tag, scmnd->device->lun, 30120a6fdbdeSBart Van Assche SRP_TSK_ABORT_TASK, NULL) == 0) 3013086f44f5SBart Van Assche ret = SUCCESS; 3014ed9b2264SBart Van Assche else if (target->rport->state == SRP_RPORT_LOST) 301599e1c139SBart Van Assche ret = FAST_IO_FAIL; 3016086f44f5SBart Van Assche else 3017086f44f5SBart Van Assche ret = FAILED; 3018e68088e7SBart Van Assche if (ret == SUCCESS) { 3019509c07bcSBart Van Assche srp_free_req(ch, req, scmnd, 0); 3020d945e1dfSRoland Dreier scmnd->result = DID_ABORT << 16; 3021d8536670SBart Van Assche scmnd->scsi_done(scmnd); 3022e68088e7SBart Van Assche } 3023d945e1dfSRoland Dreier 3024086f44f5SBart Van Assche return ret; 3025aef9ec39SRoland Dreier } 3026aef9ec39SRoland Dreier 3027aef9ec39SRoland Dreier static int srp_reset_device(struct scsi_cmnd *scmnd) 3028aef9ec39SRoland Dreier { 3029d945e1dfSRoland Dreier struct srp_target_port *target = host_to_target(scmnd->device->host); 3030d92c0da7SBart Van Assche struct srp_rdma_ch *ch; 30310a6fdbdeSBart Van Assche u8 status; 3032d945e1dfSRoland Dreier 30337aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, "SRP reset_device called\n"); 3034aef9ec39SRoland Dreier 3035d92c0da7SBart Van Assche ch = &target->ch[0]; 3036509c07bcSBart Van Assche if (srp_send_tsk_mgmt(ch, SRP_TAG_NO_REQ, scmnd->device->lun, 30370a6fdbdeSBart Van Assche SRP_TSK_LUN_RESET, &status)) 3038d945e1dfSRoland Dreier return FAILED; 30390a6fdbdeSBart Van Assche if (status) 3040d945e1dfSRoland Dreier return FAILED; 3041d945e1dfSRoland Dreier 3042d945e1dfSRoland Dreier return SUCCESS; 3043aef9ec39SRoland Dreier } 3044aef9ec39SRoland Dreier 3045aef9ec39SRoland Dreier static int srp_reset_host(struct scsi_cmnd *scmnd) 3046aef9ec39SRoland Dreier { 3047aef9ec39SRoland Dreier struct srp_target_port *target = host_to_target(scmnd->device->host); 3048aef9ec39SRoland Dreier 30497aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX "SRP reset_host called\n"); 3050aef9ec39SRoland Dreier 3051ed9b2264SBart Van Assche return srp_reconnect_rport(target->rport) == 0 ? SUCCESS : FAILED; 3052aef9ec39SRoland Dreier } 3053aef9ec39SRoland Dreier 3054b0780ee5SBart Van Assche static int srp_target_alloc(struct scsi_target *starget) 3055b0780ee5SBart Van Assche { 3056b0780ee5SBart Van Assche struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); 3057b0780ee5SBart Van Assche struct srp_target_port *target = host_to_target(shost); 3058b0780ee5SBart Van Assche 3059b0780ee5SBart Van Assche if (target->target_can_queue) 3060b0780ee5SBart Van Assche starget->can_queue = target->target_can_queue; 3061b0780ee5SBart Van Assche return 0; 3062b0780ee5SBart Van Assche } 3063b0780ee5SBart Van Assche 3064509c5f33SBart Van Assche static int srp_slave_alloc(struct scsi_device *sdev) 3065509c5f33SBart Van Assche { 3066509c5f33SBart Van Assche struct Scsi_Host *shost = sdev->host; 3067509c5f33SBart Van Assche struct srp_target_port *target = host_to_target(shost); 3068509c5f33SBart Van Assche struct srp_device *srp_dev = target->srp_host->srp_dev; 3069fbd36818SSergey Gorenko struct ib_device *ibdev = srp_dev->dev; 3070509c5f33SBart Van Assche 3071fbd36818SSergey Gorenko if (!(ibdev->attrs.device_cap_flags & IB_DEVICE_SG_GAPS_REG)) 3072509c5f33SBart Van Assche blk_queue_virt_boundary(sdev->request_queue, 3073509c5f33SBart Van Assche ~srp_dev->mr_page_mask); 3074509c5f33SBart Van Assche 3075509c5f33SBart Van Assche return 0; 3076509c5f33SBart Van Assche } 3077509c5f33SBart Van Assche 3078c9b03c1aSBart Van Assche static int srp_slave_configure(struct scsi_device *sdev) 3079c9b03c1aSBart Van Assche { 3080c9b03c1aSBart Van Assche struct Scsi_Host *shost = sdev->host; 3081c9b03c1aSBart Van Assche struct srp_target_port *target = host_to_target(shost); 3082c9b03c1aSBart Van Assche struct request_queue *q = sdev->request_queue; 3083c9b03c1aSBart Van Assche unsigned long timeout; 3084c9b03c1aSBart Van Assche 3085c9b03c1aSBart Van Assche if (sdev->type == TYPE_DISK) { 3086c9b03c1aSBart Van Assche timeout = max_t(unsigned, 30 * HZ, target->rq_tmo_jiffies); 3087c9b03c1aSBart Van Assche blk_queue_rq_timeout(q, timeout); 3088c9b03c1aSBart Van Assche } 3089c9b03c1aSBart Van Assche 3090c9b03c1aSBart Van Assche return 0; 3091c9b03c1aSBart Van Assche } 3092c9b03c1aSBart Van Assche 3093ee959b00STony Jones static ssize_t show_id_ext(struct device *dev, struct device_attribute *attr, 3094ee959b00STony Jones char *buf) 30956ecb0c84SRoland Dreier { 3096ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 30976ecb0c84SRoland Dreier 309845c37cadSBart Van Assche return sprintf(buf, "0x%016llx\n", be64_to_cpu(target->id_ext)); 30996ecb0c84SRoland Dreier } 31006ecb0c84SRoland Dreier 3101ee959b00STony Jones static ssize_t show_ioc_guid(struct device *dev, struct device_attribute *attr, 3102ee959b00STony Jones char *buf) 31036ecb0c84SRoland Dreier { 3104ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 31056ecb0c84SRoland Dreier 310645c37cadSBart Van Assche return sprintf(buf, "0x%016llx\n", be64_to_cpu(target->ioc_guid)); 31076ecb0c84SRoland Dreier } 31086ecb0c84SRoland Dreier 3109ee959b00STony Jones static ssize_t show_service_id(struct device *dev, 3110ee959b00STony Jones struct device_attribute *attr, char *buf) 31116ecb0c84SRoland Dreier { 3112ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 31136ecb0c84SRoland Dreier 311419f31343SBart Van Assche if (target->using_rdma_cm) 311519f31343SBart Van Assche return -ENOENT; 311619f31343SBart Van Assche return sprintf(buf, "0x%016llx\n", 311719f31343SBart Van Assche be64_to_cpu(target->ib_cm.service_id)); 31186ecb0c84SRoland Dreier } 31196ecb0c84SRoland Dreier 3120ee959b00STony Jones static ssize_t show_pkey(struct device *dev, struct device_attribute *attr, 3121ee959b00STony Jones char *buf) 31226ecb0c84SRoland Dreier { 3123ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 31246ecb0c84SRoland Dreier 312519f31343SBart Van Assche if (target->using_rdma_cm) 312619f31343SBart Van Assche return -ENOENT; 312719f31343SBart Van Assche return sprintf(buf, "0x%04x\n", be16_to_cpu(target->ib_cm.pkey)); 31286ecb0c84SRoland Dreier } 31296ecb0c84SRoland Dreier 3130848b3082SBart Van Assche static ssize_t show_sgid(struct device *dev, struct device_attribute *attr, 3131848b3082SBart Van Assche char *buf) 3132848b3082SBart Van Assche { 3133848b3082SBart Van Assche struct srp_target_port *target = host_to_target(class_to_shost(dev)); 3134848b3082SBart Van Assche 3135747fe000SBart Van Assche return sprintf(buf, "%pI6\n", target->sgid.raw); 3136848b3082SBart Van Assche } 3137848b3082SBart Van Assche 3138ee959b00STony Jones static ssize_t show_dgid(struct device *dev, struct device_attribute *attr, 3139ee959b00STony Jones char *buf) 31406ecb0c84SRoland Dreier { 3141ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 3142d92c0da7SBart Van Assche struct srp_rdma_ch *ch = &target->ch[0]; 31436ecb0c84SRoland Dreier 314419f31343SBart Van Assche if (target->using_rdma_cm) 314519f31343SBart Van Assche return -ENOENT; 314619f31343SBart Van Assche return sprintf(buf, "%pI6\n", ch->ib_cm.path.dgid.raw); 31476ecb0c84SRoland Dreier } 31486ecb0c84SRoland Dreier 3149ee959b00STony Jones static ssize_t show_orig_dgid(struct device *dev, 3150ee959b00STony Jones struct device_attribute *attr, char *buf) 31513633b3d0SIshai Rabinovitz { 3152ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 31533633b3d0SIshai Rabinovitz 315419f31343SBart Van Assche if (target->using_rdma_cm) 315519f31343SBart Van Assche return -ENOENT; 315619f31343SBart Van Assche return sprintf(buf, "%pI6\n", target->ib_cm.orig_dgid.raw); 31573633b3d0SIshai Rabinovitz } 31583633b3d0SIshai Rabinovitz 315989de7486SBart Van Assche static ssize_t show_req_lim(struct device *dev, 316089de7486SBart Van Assche struct device_attribute *attr, char *buf) 316189de7486SBart Van Assche { 316289de7486SBart Van Assche struct srp_target_port *target = host_to_target(class_to_shost(dev)); 3163d92c0da7SBart Van Assche struct srp_rdma_ch *ch; 3164d92c0da7SBart Van Assche int i, req_lim = INT_MAX; 316589de7486SBart Van Assche 3166d92c0da7SBart Van Assche for (i = 0; i < target->ch_count; i++) { 3167d92c0da7SBart Van Assche ch = &target->ch[i]; 3168d92c0da7SBart Van Assche req_lim = min(req_lim, ch->req_lim); 3169d92c0da7SBart Van Assche } 3170d92c0da7SBart Van Assche return sprintf(buf, "%d\n", req_lim); 317189de7486SBart Van Assche } 317289de7486SBart Van Assche 3173ee959b00STony Jones static ssize_t show_zero_req_lim(struct device *dev, 3174ee959b00STony Jones struct device_attribute *attr, char *buf) 31756bfa24faSRoland Dreier { 3176ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 31776bfa24faSRoland Dreier 31786bfa24faSRoland Dreier return sprintf(buf, "%d\n", target->zero_req_lim); 31796bfa24faSRoland Dreier } 31806bfa24faSRoland Dreier 3181ee959b00STony Jones static ssize_t show_local_ib_port(struct device *dev, 3182ee959b00STony Jones struct device_attribute *attr, char *buf) 3183ded7f1a1SIshai Rabinovitz { 3184ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 3185ded7f1a1SIshai Rabinovitz 3186ded7f1a1SIshai Rabinovitz return sprintf(buf, "%d\n", target->srp_host->port); 3187ded7f1a1SIshai Rabinovitz } 3188ded7f1a1SIshai Rabinovitz 3189ee959b00STony Jones static ssize_t show_local_ib_device(struct device *dev, 3190ee959b00STony Jones struct device_attribute *attr, char *buf) 3191ded7f1a1SIshai Rabinovitz { 3192ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 3193ded7f1a1SIshai Rabinovitz 31946c854111SJason Gunthorpe return sprintf(buf, "%s\n", 31956c854111SJason Gunthorpe dev_name(&target->srp_host->srp_dev->dev->dev)); 3196ded7f1a1SIshai Rabinovitz } 3197ded7f1a1SIshai Rabinovitz 3198d92c0da7SBart Van Assche static ssize_t show_ch_count(struct device *dev, struct device_attribute *attr, 3199d92c0da7SBart Van Assche char *buf) 3200d92c0da7SBart Van Assche { 3201d92c0da7SBart Van Assche struct srp_target_port *target = host_to_target(class_to_shost(dev)); 3202d92c0da7SBart Van Assche 3203d92c0da7SBart Van Assche return sprintf(buf, "%d\n", target->ch_count); 3204d92c0da7SBart Van Assche } 3205d92c0da7SBart Van Assche 32064b5e5f41SBart Van Assche static ssize_t show_comp_vector(struct device *dev, 32074b5e5f41SBart Van Assche struct device_attribute *attr, char *buf) 32084b5e5f41SBart Van Assche { 32094b5e5f41SBart Van Assche struct srp_target_port *target = host_to_target(class_to_shost(dev)); 32104b5e5f41SBart Van Assche 32114b5e5f41SBart Van Assche return sprintf(buf, "%d\n", target->comp_vector); 32124b5e5f41SBart Van Assche } 32134b5e5f41SBart Van Assche 32147bb312e4SVu Pham static ssize_t show_tl_retry_count(struct device *dev, 32157bb312e4SVu Pham struct device_attribute *attr, char *buf) 32167bb312e4SVu Pham { 32177bb312e4SVu Pham struct srp_target_port *target = host_to_target(class_to_shost(dev)); 32187bb312e4SVu Pham 32197bb312e4SVu Pham return sprintf(buf, "%d\n", target->tl_retry_count); 32207bb312e4SVu Pham } 32217bb312e4SVu Pham 322249248644SDavid Dillow static ssize_t show_cmd_sg_entries(struct device *dev, 322349248644SDavid Dillow struct device_attribute *attr, char *buf) 322449248644SDavid Dillow { 322549248644SDavid Dillow struct srp_target_port *target = host_to_target(class_to_shost(dev)); 322649248644SDavid Dillow 322749248644SDavid Dillow return sprintf(buf, "%u\n", target->cmd_sg_cnt); 322849248644SDavid Dillow } 322949248644SDavid Dillow 3230c07d424dSDavid Dillow static ssize_t show_allow_ext_sg(struct device *dev, 3231c07d424dSDavid Dillow struct device_attribute *attr, char *buf) 3232c07d424dSDavid Dillow { 3233c07d424dSDavid Dillow struct srp_target_port *target = host_to_target(class_to_shost(dev)); 3234c07d424dSDavid Dillow 3235c07d424dSDavid Dillow return sprintf(buf, "%s\n", target->allow_ext_sg ? "true" : "false"); 3236c07d424dSDavid Dillow } 3237c07d424dSDavid Dillow 3238ee959b00STony Jones static DEVICE_ATTR(id_ext, S_IRUGO, show_id_ext, NULL); 3239ee959b00STony Jones static DEVICE_ATTR(ioc_guid, S_IRUGO, show_ioc_guid, NULL); 3240ee959b00STony Jones static DEVICE_ATTR(service_id, S_IRUGO, show_service_id, NULL); 3241ee959b00STony Jones static DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL); 3242848b3082SBart Van Assche static DEVICE_ATTR(sgid, S_IRUGO, show_sgid, NULL); 3243ee959b00STony Jones static DEVICE_ATTR(dgid, S_IRUGO, show_dgid, NULL); 3244ee959b00STony Jones static DEVICE_ATTR(orig_dgid, S_IRUGO, show_orig_dgid, NULL); 324589de7486SBart Van Assche static DEVICE_ATTR(req_lim, S_IRUGO, show_req_lim, NULL); 3246ee959b00STony Jones static DEVICE_ATTR(zero_req_lim, S_IRUGO, show_zero_req_lim, NULL); 3247ee959b00STony Jones static DEVICE_ATTR(local_ib_port, S_IRUGO, show_local_ib_port, NULL); 3248ee959b00STony Jones static DEVICE_ATTR(local_ib_device, S_IRUGO, show_local_ib_device, NULL); 3249d92c0da7SBart Van Assche static DEVICE_ATTR(ch_count, S_IRUGO, show_ch_count, NULL); 32504b5e5f41SBart Van Assche static DEVICE_ATTR(comp_vector, S_IRUGO, show_comp_vector, NULL); 32517bb312e4SVu Pham static DEVICE_ATTR(tl_retry_count, S_IRUGO, show_tl_retry_count, NULL); 325249248644SDavid Dillow static DEVICE_ATTR(cmd_sg_entries, S_IRUGO, show_cmd_sg_entries, NULL); 3253c07d424dSDavid Dillow static DEVICE_ATTR(allow_ext_sg, S_IRUGO, show_allow_ext_sg, NULL); 32546ecb0c84SRoland Dreier 3255ee959b00STony Jones static struct device_attribute *srp_host_attrs[] = { 3256ee959b00STony Jones &dev_attr_id_ext, 3257ee959b00STony Jones &dev_attr_ioc_guid, 3258ee959b00STony Jones &dev_attr_service_id, 3259ee959b00STony Jones &dev_attr_pkey, 3260848b3082SBart Van Assche &dev_attr_sgid, 3261ee959b00STony Jones &dev_attr_dgid, 3262ee959b00STony Jones &dev_attr_orig_dgid, 326389de7486SBart Van Assche &dev_attr_req_lim, 3264ee959b00STony Jones &dev_attr_zero_req_lim, 3265ee959b00STony Jones &dev_attr_local_ib_port, 3266ee959b00STony Jones &dev_attr_local_ib_device, 3267d92c0da7SBart Van Assche &dev_attr_ch_count, 32684b5e5f41SBart Van Assche &dev_attr_comp_vector, 32697bb312e4SVu Pham &dev_attr_tl_retry_count, 327049248644SDavid Dillow &dev_attr_cmd_sg_entries, 3271c07d424dSDavid Dillow &dev_attr_allow_ext_sg, 32726ecb0c84SRoland Dreier NULL 32736ecb0c84SRoland Dreier }; 32746ecb0c84SRoland Dreier 3275aef9ec39SRoland Dreier static struct scsi_host_template srp_template = { 3276aef9ec39SRoland Dreier .module = THIS_MODULE, 3277b7f008fdSRoland Dreier .name = "InfiniBand SRP initiator", 3278b7f008fdSRoland Dreier .proc_name = DRV_NAME, 3279b0780ee5SBart Van Assche .target_alloc = srp_target_alloc, 3280509c5f33SBart Van Assche .slave_alloc = srp_slave_alloc, 3281c9b03c1aSBart Van Assche .slave_configure = srp_slave_configure, 3282aef9ec39SRoland Dreier .info = srp_target_info, 3283aef9ec39SRoland Dreier .queuecommand = srp_queuecommand, 328471444b97SJack Wang .change_queue_depth = srp_change_queue_depth, 3285b6a05c82SChristoph Hellwig .eh_timed_out = srp_timed_out, 3286aef9ec39SRoland Dreier .eh_abort_handler = srp_abort, 3287aef9ec39SRoland Dreier .eh_device_reset_handler = srp_reset_device, 3288aef9ec39SRoland Dreier .eh_host_reset_handler = srp_reset_host, 32892742c1daSBart Van Assche .skip_settle_delay = true, 329049248644SDavid Dillow .sg_tablesize = SRP_DEF_SG_TABLESIZE, 32914d73f95fSBart Van Assche .can_queue = SRP_DEFAULT_CMD_SQ_SIZE, 3292aef9ec39SRoland Dreier .this_id = -1, 32934d73f95fSBart Van Assche .cmd_per_lun = SRP_DEFAULT_CMD_SQ_SIZE, 329477f2c1a4SBart Van Assche .shost_attrs = srp_host_attrs, 3295c40ecc12SChristoph Hellwig .track_queue_depth = 1, 3296aef9ec39SRoland Dreier }; 3297aef9ec39SRoland Dreier 329834aa654eSBart Van Assche static int srp_sdev_count(struct Scsi_Host *host) 329934aa654eSBart Van Assche { 330034aa654eSBart Van Assche struct scsi_device *sdev; 330134aa654eSBart Van Assche int c = 0; 330234aa654eSBart Van Assche 330334aa654eSBart Van Assche shost_for_each_device(sdev, host) 330434aa654eSBart Van Assche c++; 330534aa654eSBart Van Assche 330634aa654eSBart Van Assche return c; 330734aa654eSBart Van Assche } 330834aa654eSBart Van Assche 3309bc44bd1dSBart Van Assche /* 3310bc44bd1dSBart Van Assche * Return values: 3311bc44bd1dSBart Van Assche * < 0 upon failure. Caller is responsible for SRP target port cleanup. 3312bc44bd1dSBart Van Assche * 0 and target->state == SRP_TARGET_REMOVED if asynchronous target port 3313bc44bd1dSBart Van Assche * removal has been scheduled. 3314bc44bd1dSBart Van Assche * 0 and target->state != SRP_TARGET_REMOVED upon success. 3315bc44bd1dSBart Van Assche */ 3316aef9ec39SRoland Dreier static int srp_add_target(struct srp_host *host, struct srp_target_port *target) 3317aef9ec39SRoland Dreier { 33183236822bSFUJITA Tomonori struct srp_rport_identifiers ids; 33193236822bSFUJITA Tomonori struct srp_rport *rport; 33203236822bSFUJITA Tomonori 332134aa654eSBart Van Assche target->state = SRP_TARGET_SCANNING; 3322aef9ec39SRoland Dreier sprintf(target->target_name, "SRP.T10:%016llX", 332345c37cadSBart Van Assche be64_to_cpu(target->id_ext)); 3324aef9ec39SRoland Dreier 3325dee2b82aSBart Van Assche if (scsi_add_host(target->scsi_host, host->srp_dev->dev->dev.parent)) 3326aef9ec39SRoland Dreier return -ENODEV; 3327aef9ec39SRoland Dreier 33283236822bSFUJITA Tomonori memcpy(ids.port_id, &target->id_ext, 8); 33293236822bSFUJITA Tomonori memcpy(ids.port_id + 8, &target->ioc_guid, 8); 3330aebd5e47SFUJITA Tomonori ids.roles = SRP_RPORT_ROLE_TARGET; 33313236822bSFUJITA Tomonori rport = srp_rport_add(target->scsi_host, &ids); 33323236822bSFUJITA Tomonori if (IS_ERR(rport)) { 33333236822bSFUJITA Tomonori scsi_remove_host(target->scsi_host); 33343236822bSFUJITA Tomonori return PTR_ERR(rport); 33353236822bSFUJITA Tomonori } 33363236822bSFUJITA Tomonori 3337dc1bdbd9SBart Van Assche rport->lld_data = target; 33389dd69a60SBart Van Assche target->rport = rport; 3339dc1bdbd9SBart Van Assche 3340b3589fd4SMatthew Wilcox spin_lock(&host->target_lock); 3341aef9ec39SRoland Dreier list_add_tail(&target->list, &host->target_list); 3342b3589fd4SMatthew Wilcox spin_unlock(&host->target_lock); 3343aef9ec39SRoland Dreier 3344aef9ec39SRoland Dreier scsi_scan_target(&target->scsi_host->shost_gendev, 33451d645088SHannes Reinecke 0, target->scsi_id, SCAN_WILD_CARD, SCSI_SCAN_INITIAL); 3346aef9ec39SRoland Dreier 3347c014c8cdSBart Van Assche if (srp_connected_ch(target) < target->ch_count || 3348c014c8cdSBart Van Assche target->qp_in_error) { 334934aa654eSBart Van Assche shost_printk(KERN_INFO, target->scsi_host, 335034aa654eSBart Van Assche PFX "SCSI scan failed - removing SCSI host\n"); 335134aa654eSBart Van Assche srp_queue_remove_work(target); 335234aa654eSBart Van Assche goto out; 335334aa654eSBart Van Assche } 335434aa654eSBart Van Assche 3355cf1acab7SBart Van Assche pr_debug("%s: SCSI scan succeeded - detected %d LUNs\n", 335634aa654eSBart Van Assche dev_name(&target->scsi_host->shost_gendev), 335734aa654eSBart Van Assche srp_sdev_count(target->scsi_host)); 335834aa654eSBart Van Assche 335934aa654eSBart Van Assche spin_lock_irq(&target->lock); 336034aa654eSBart Van Assche if (target->state == SRP_TARGET_SCANNING) 336134aa654eSBart Van Assche target->state = SRP_TARGET_LIVE; 336234aa654eSBart Van Assche spin_unlock_irq(&target->lock); 336334aa654eSBart Van Assche 336434aa654eSBart Van Assche out: 3365aef9ec39SRoland Dreier return 0; 3366aef9ec39SRoland Dreier } 3367aef9ec39SRoland Dreier 3368ee959b00STony Jones static void srp_release_dev(struct device *dev) 3369aef9ec39SRoland Dreier { 3370aef9ec39SRoland Dreier struct srp_host *host = 3371ee959b00STony Jones container_of(dev, struct srp_host, dev); 3372aef9ec39SRoland Dreier 3373aef9ec39SRoland Dreier complete(&host->released); 3374aef9ec39SRoland Dreier } 3375aef9ec39SRoland Dreier 3376aef9ec39SRoland Dreier static struct class srp_class = { 3377aef9ec39SRoland Dreier .name = "infiniband_srp", 3378ee959b00STony Jones .dev_release = srp_release_dev 3379aef9ec39SRoland Dreier }; 3380aef9ec39SRoland Dreier 338196fc248aSBart Van Assche /** 338296fc248aSBart Van Assche * srp_conn_unique() - check whether the connection to a target is unique 3383af24663bSBart Van Assche * @host: SRP host. 3384af24663bSBart Van Assche * @target: SRP target port. 338596fc248aSBart Van Assche */ 338696fc248aSBart Van Assche static bool srp_conn_unique(struct srp_host *host, 338796fc248aSBart Van Assche struct srp_target_port *target) 338896fc248aSBart Van Assche { 338996fc248aSBart Van Assche struct srp_target_port *t; 339096fc248aSBart Van Assche bool ret = false; 339196fc248aSBart Van Assche 339296fc248aSBart Van Assche if (target->state == SRP_TARGET_REMOVED) 339396fc248aSBart Van Assche goto out; 339496fc248aSBart Van Assche 339596fc248aSBart Van Assche ret = true; 339696fc248aSBart Van Assche 339796fc248aSBart Van Assche spin_lock(&host->target_lock); 339896fc248aSBart Van Assche list_for_each_entry(t, &host->target_list, list) { 339996fc248aSBart Van Assche if (t != target && 340096fc248aSBart Van Assche target->id_ext == t->id_ext && 340196fc248aSBart Van Assche target->ioc_guid == t->ioc_guid && 340296fc248aSBart Van Assche target->initiator_ext == t->initiator_ext) { 340396fc248aSBart Van Assche ret = false; 340496fc248aSBart Van Assche break; 340596fc248aSBart Van Assche } 340696fc248aSBart Van Assche } 340796fc248aSBart Van Assche spin_unlock(&host->target_lock); 340896fc248aSBart Van Assche 340996fc248aSBart Van Assche out: 341096fc248aSBart Van Assche return ret; 341196fc248aSBart Van Assche } 341296fc248aSBart Van Assche 3413aef9ec39SRoland Dreier /* 3414aef9ec39SRoland Dreier * Target ports are added by writing 3415aef9ec39SRoland Dreier * 3416aef9ec39SRoland Dreier * id_ext=<SRP ID ext>,ioc_guid=<SRP IOC GUID>,dgid=<dest GID>, 3417aef9ec39SRoland Dreier * pkey=<P_Key>,service_id=<service ID> 341819f31343SBart Van Assche * or 341919f31343SBart Van Assche * id_ext=<SRP ID ext>,ioc_guid=<SRP IOC GUID>, 342019f31343SBart Van Assche * [src=<IPv4 address>,]dest=<IPv4 address>:<port number> 3421aef9ec39SRoland Dreier * 3422aef9ec39SRoland Dreier * to the add_target sysfs attribute. 3423aef9ec39SRoland Dreier */ 3424aef9ec39SRoland Dreier enum { 3425aef9ec39SRoland Dreier SRP_OPT_ERR = 0, 3426aef9ec39SRoland Dreier SRP_OPT_ID_EXT = 1 << 0, 3427aef9ec39SRoland Dreier SRP_OPT_IOC_GUID = 1 << 1, 3428aef9ec39SRoland Dreier SRP_OPT_DGID = 1 << 2, 3429aef9ec39SRoland Dreier SRP_OPT_PKEY = 1 << 3, 3430aef9ec39SRoland Dreier SRP_OPT_SERVICE_ID = 1 << 4, 3431aef9ec39SRoland Dreier SRP_OPT_MAX_SECT = 1 << 5, 343252fb2b50SVu Pham SRP_OPT_MAX_CMD_PER_LUN = 1 << 6, 34330c0450dbSRamachandra K SRP_OPT_IO_CLASS = 1 << 7, 343401cb9bcbSIshai Rabinovitz SRP_OPT_INITIATOR_EXT = 1 << 8, 343549248644SDavid Dillow SRP_OPT_CMD_SG_ENTRIES = 1 << 9, 3436c07d424dSDavid Dillow SRP_OPT_ALLOW_EXT_SG = 1 << 10, 3437c07d424dSDavid Dillow SRP_OPT_SG_TABLESIZE = 1 << 11, 34384b5e5f41SBart Van Assche SRP_OPT_COMP_VECTOR = 1 << 12, 34397bb312e4SVu Pham SRP_OPT_TL_RETRY_COUNT = 1 << 13, 34404d73f95fSBart Van Assche SRP_OPT_QUEUE_SIZE = 1 << 14, 344119f31343SBart Van Assche SRP_OPT_IP_SRC = 1 << 15, 344219f31343SBart Van Assche SRP_OPT_IP_DEST = 1 << 16, 3443b0780ee5SBart Van Assche SRP_OPT_TARGET_CAN_QUEUE= 1 << 17, 344419f31343SBart Van Assche }; 344519f31343SBart Van Assche 344619f31343SBart Van Assche static unsigned int srp_opt_mandatory[] = { 344719f31343SBart Van Assche SRP_OPT_ID_EXT | 3448aef9ec39SRoland Dreier SRP_OPT_IOC_GUID | 3449aef9ec39SRoland Dreier SRP_OPT_DGID | 3450aef9ec39SRoland Dreier SRP_OPT_PKEY | 345119f31343SBart Van Assche SRP_OPT_SERVICE_ID, 345219f31343SBart Van Assche SRP_OPT_ID_EXT | 345319f31343SBart Van Assche SRP_OPT_IOC_GUID | 345419f31343SBart Van Assche SRP_OPT_IP_DEST, 3455aef9ec39SRoland Dreier }; 3456aef9ec39SRoland Dreier 3457a447c093SSteven Whitehouse static const match_table_t srp_opt_tokens = { 3458aef9ec39SRoland Dreier { SRP_OPT_ID_EXT, "id_ext=%s" }, 3459aef9ec39SRoland Dreier { SRP_OPT_IOC_GUID, "ioc_guid=%s" }, 3460aef9ec39SRoland Dreier { SRP_OPT_DGID, "dgid=%s" }, 3461aef9ec39SRoland Dreier { SRP_OPT_PKEY, "pkey=%x" }, 3462aef9ec39SRoland Dreier { SRP_OPT_SERVICE_ID, "service_id=%s" }, 3463aef9ec39SRoland Dreier { SRP_OPT_MAX_SECT, "max_sect=%d" }, 346452fb2b50SVu Pham { SRP_OPT_MAX_CMD_PER_LUN, "max_cmd_per_lun=%d" }, 3465b0780ee5SBart Van Assche { SRP_OPT_TARGET_CAN_QUEUE, "target_can_queue=%d" }, 34660c0450dbSRamachandra K { SRP_OPT_IO_CLASS, "io_class=%x" }, 346701cb9bcbSIshai Rabinovitz { SRP_OPT_INITIATOR_EXT, "initiator_ext=%s" }, 346849248644SDavid Dillow { SRP_OPT_CMD_SG_ENTRIES, "cmd_sg_entries=%u" }, 3469c07d424dSDavid Dillow { SRP_OPT_ALLOW_EXT_SG, "allow_ext_sg=%u" }, 3470c07d424dSDavid Dillow { SRP_OPT_SG_TABLESIZE, "sg_tablesize=%u" }, 34714b5e5f41SBart Van Assche { SRP_OPT_COMP_VECTOR, "comp_vector=%u" }, 34727bb312e4SVu Pham { SRP_OPT_TL_RETRY_COUNT, "tl_retry_count=%u" }, 34734d73f95fSBart Van Assche { SRP_OPT_QUEUE_SIZE, "queue_size=%d" }, 347419f31343SBart Van Assche { SRP_OPT_IP_SRC, "src=%s" }, 347519f31343SBart Van Assche { SRP_OPT_IP_DEST, "dest=%s" }, 3476aef9ec39SRoland Dreier { SRP_OPT_ERR, NULL } 3477aef9ec39SRoland Dreier }; 3478aef9ec39SRoland Dreier 3479c62adb7dSBart Van Assche /** 3480c62adb7dSBart Van Assche * srp_parse_in - parse an IP address and port number combination 3481e37df2d5SBart Van Assche * @net: [in] Network namespace. 3482e37df2d5SBart Van Assche * @sa: [out] Address family, IP address and port number. 3483e37df2d5SBart Van Assche * @addr_port_str: [in] IP address and port number. 3484*bcef5b72SBart Van Assche * @has_port: [out] Whether or not @addr_port_str includes a port number. 3485c62adb7dSBart Van Assche * 3486c62adb7dSBart Van Assche * Parse the following address formats: 3487c62adb7dSBart Van Assche * - IPv4: <ip_address>:<port>, e.g. 1.2.3.4:5. 3488c62adb7dSBart Van Assche * - IPv6: \[<ipv6_address>\]:<port>, e.g. [1::2:3%4]:5. 3489c62adb7dSBart Van Assche */ 349019f31343SBart Van Assche static int srp_parse_in(struct net *net, struct sockaddr_storage *sa, 3491*bcef5b72SBart Van Assche const char *addr_port_str, bool *has_port) 349219f31343SBart Van Assche { 3493c62adb7dSBart Van Assche char *addr_end, *addr = kstrdup(addr_port_str, GFP_KERNEL); 3494c62adb7dSBart Van Assche char *port_str; 349519f31343SBart Van Assche int ret; 349619f31343SBart Van Assche 349719f31343SBart Van Assche if (!addr) 349819f31343SBart Van Assche return -ENOMEM; 3499c62adb7dSBart Van Assche port_str = strrchr(addr, ':'); 3500*bcef5b72SBart Van Assche if (port_str && strchr(port_str, ']')) 3501*bcef5b72SBart Van Assche port_str = NULL; 3502*bcef5b72SBart Van Assche if (port_str) 3503c62adb7dSBart Van Assche *port_str++ = '\0'; 3504*bcef5b72SBart Van Assche if (has_port) 3505*bcef5b72SBart Van Assche *has_port = port_str != NULL; 3506c62adb7dSBart Van Assche ret = inet_pton_with_scope(net, AF_INET, addr, port_str, sa); 3507c62adb7dSBart Van Assche if (ret && addr[0]) { 3508c62adb7dSBart Van Assche addr_end = addr + strlen(addr) - 1; 3509c62adb7dSBart Van Assche if (addr[0] == '[' && *addr_end == ']') { 3510c62adb7dSBart Van Assche *addr_end = '\0'; 3511c62adb7dSBart Van Assche ret = inet_pton_with_scope(net, AF_INET6, addr + 1, 3512c62adb7dSBart Van Assche port_str, sa); 3513c62adb7dSBart Van Assche } 3514c62adb7dSBart Van Assche } 351519f31343SBart Van Assche kfree(addr); 3516c62adb7dSBart Van Assche pr_debug("%s -> %pISpfsc\n", addr_port_str, sa); 351719f31343SBart Van Assche return ret; 351819f31343SBart Van Assche } 351919f31343SBart Van Assche 352019f31343SBart Van Assche static int srp_parse_options(struct net *net, const char *buf, 352119f31343SBart Van Assche struct srp_target_port *target) 3522aef9ec39SRoland Dreier { 3523aef9ec39SRoland Dreier char *options, *sep_opt; 3524aef9ec39SRoland Dreier char *p; 3525aef9ec39SRoland Dreier substring_t args[MAX_OPT_ARGS]; 35262a174df0SBart Van Assche unsigned long long ull; 3527*bcef5b72SBart Van Assche bool has_port; 3528aef9ec39SRoland Dreier int opt_mask = 0; 3529aef9ec39SRoland Dreier int token; 3530aef9ec39SRoland Dreier int ret = -EINVAL; 3531aef9ec39SRoland Dreier int i; 3532aef9ec39SRoland Dreier 3533aef9ec39SRoland Dreier options = kstrdup(buf, GFP_KERNEL); 3534aef9ec39SRoland Dreier if (!options) 3535aef9ec39SRoland Dreier return -ENOMEM; 3536aef9ec39SRoland Dreier 3537aef9ec39SRoland Dreier sep_opt = options; 35387dcf9c19SSagi Grimberg while ((p = strsep(&sep_opt, ",\n")) != NULL) { 3539aef9ec39SRoland Dreier if (!*p) 3540aef9ec39SRoland Dreier continue; 3541aef9ec39SRoland Dreier 3542aef9ec39SRoland Dreier token = match_token(p, srp_opt_tokens, args); 3543aef9ec39SRoland Dreier opt_mask |= token; 3544aef9ec39SRoland Dreier 3545aef9ec39SRoland Dreier switch (token) { 3546aef9ec39SRoland Dreier case SRP_OPT_ID_EXT: 3547aef9ec39SRoland Dreier p = match_strdup(args); 3548a20f3a6dSIshai Rabinovitz if (!p) { 3549a20f3a6dSIshai Rabinovitz ret = -ENOMEM; 3550a20f3a6dSIshai Rabinovitz goto out; 3551a20f3a6dSIshai Rabinovitz } 35522a174df0SBart Van Assche ret = kstrtoull(p, 16, &ull); 35532a174df0SBart Van Assche if (ret) { 35542a174df0SBart Van Assche pr_warn("invalid id_ext parameter '%s'\n", p); 35552a174df0SBart Van Assche kfree(p); 35562a174df0SBart Van Assche goto out; 35572a174df0SBart Van Assche } 35582a174df0SBart Van Assche target->id_ext = cpu_to_be64(ull); 3559aef9ec39SRoland Dreier kfree(p); 3560aef9ec39SRoland Dreier break; 3561aef9ec39SRoland Dreier 3562aef9ec39SRoland Dreier case SRP_OPT_IOC_GUID: 3563aef9ec39SRoland Dreier p = match_strdup(args); 3564a20f3a6dSIshai Rabinovitz if (!p) { 3565a20f3a6dSIshai Rabinovitz ret = -ENOMEM; 3566a20f3a6dSIshai Rabinovitz goto out; 3567a20f3a6dSIshai Rabinovitz } 35682a174df0SBart Van Assche ret = kstrtoull(p, 16, &ull); 35692a174df0SBart Van Assche if (ret) { 35702a174df0SBart Van Assche pr_warn("invalid ioc_guid parameter '%s'\n", p); 35712a174df0SBart Van Assche kfree(p); 35722a174df0SBart Van Assche goto out; 35732a174df0SBart Van Assche } 35742a174df0SBart Van Assche target->ioc_guid = cpu_to_be64(ull); 3575aef9ec39SRoland Dreier kfree(p); 3576aef9ec39SRoland Dreier break; 3577aef9ec39SRoland Dreier 3578aef9ec39SRoland Dreier case SRP_OPT_DGID: 3579aef9ec39SRoland Dreier p = match_strdup(args); 3580a20f3a6dSIshai Rabinovitz if (!p) { 3581a20f3a6dSIshai Rabinovitz ret = -ENOMEM; 3582a20f3a6dSIshai Rabinovitz goto out; 3583a20f3a6dSIshai Rabinovitz } 3584aef9ec39SRoland Dreier if (strlen(p) != 32) { 3585e0bda7d8SBart Van Assche pr_warn("bad dest GID parameter '%s'\n", p); 3586ce1823f0SRoland Dreier kfree(p); 3587aef9ec39SRoland Dreier goto out; 3588aef9ec39SRoland Dreier } 3589aef9ec39SRoland Dreier 359019f31343SBart Van Assche ret = hex2bin(target->ib_cm.orig_dgid.raw, p, 16); 3591747fe000SBart Van Assche kfree(p); 3592e711f968SAndy Shevchenko if (ret < 0) 3593747fe000SBart Van Assche goto out; 3594aef9ec39SRoland Dreier break; 3595aef9ec39SRoland Dreier 3596aef9ec39SRoland Dreier case SRP_OPT_PKEY: 3597aef9ec39SRoland Dreier if (match_hex(args, &token)) { 3598e0bda7d8SBart Van Assche pr_warn("bad P_Key parameter '%s'\n", p); 3599aef9ec39SRoland Dreier goto out; 3600aef9ec39SRoland Dreier } 360119f31343SBart Van Assche target->ib_cm.pkey = cpu_to_be16(token); 3602aef9ec39SRoland Dreier break; 3603aef9ec39SRoland Dreier 3604aef9ec39SRoland Dreier case SRP_OPT_SERVICE_ID: 3605aef9ec39SRoland Dreier p = match_strdup(args); 3606a20f3a6dSIshai Rabinovitz if (!p) { 3607a20f3a6dSIshai Rabinovitz ret = -ENOMEM; 3608a20f3a6dSIshai Rabinovitz goto out; 3609a20f3a6dSIshai Rabinovitz } 36102a174df0SBart Van Assche ret = kstrtoull(p, 16, &ull); 36112a174df0SBart Van Assche if (ret) { 36122a174df0SBart Van Assche pr_warn("bad service_id parameter '%s'\n", p); 36132a174df0SBart Van Assche kfree(p); 36142a174df0SBart Van Assche goto out; 36152a174df0SBart Van Assche } 361619f31343SBart Van Assche target->ib_cm.service_id = cpu_to_be64(ull); 361719f31343SBart Van Assche kfree(p); 361819f31343SBart Van Assche break; 361919f31343SBart Van Assche 362019f31343SBart Van Assche case SRP_OPT_IP_SRC: 362119f31343SBart Van Assche p = match_strdup(args); 362219f31343SBart Van Assche if (!p) { 362319f31343SBart Van Assche ret = -ENOMEM; 362419f31343SBart Van Assche goto out; 362519f31343SBart Van Assche } 3626*bcef5b72SBart Van Assche ret = srp_parse_in(net, &target->rdma_cm.src.ss, p, 3627*bcef5b72SBart Van Assche NULL); 362819f31343SBart Van Assche if (ret < 0) { 362919f31343SBart Van Assche pr_warn("bad source parameter '%s'\n", p); 363019f31343SBart Van Assche kfree(p); 363119f31343SBart Van Assche goto out; 363219f31343SBart Van Assche } 363319f31343SBart Van Assche target->rdma_cm.src_specified = true; 363419f31343SBart Van Assche kfree(p); 363519f31343SBart Van Assche break; 363619f31343SBart Van Assche 363719f31343SBart Van Assche case SRP_OPT_IP_DEST: 363819f31343SBart Van Assche p = match_strdup(args); 363919f31343SBart Van Assche if (!p) { 364019f31343SBart Van Assche ret = -ENOMEM; 364119f31343SBart Van Assche goto out; 364219f31343SBart Van Assche } 3643*bcef5b72SBart Van Assche ret = srp_parse_in(net, &target->rdma_cm.dst.ss, p, 3644*bcef5b72SBart Van Assche &has_port); 3645*bcef5b72SBart Van Assche if (!has_port) 3646*bcef5b72SBart Van Assche ret = -EINVAL; 364719f31343SBart Van Assche if (ret < 0) { 364819f31343SBart Van Assche pr_warn("bad dest parameter '%s'\n", p); 364919f31343SBart Van Assche kfree(p); 365019f31343SBart Van Assche goto out; 365119f31343SBart Van Assche } 365219f31343SBart Van Assche target->using_rdma_cm = true; 3653aef9ec39SRoland Dreier kfree(p); 3654aef9ec39SRoland Dreier break; 3655aef9ec39SRoland Dreier 3656aef9ec39SRoland Dreier case SRP_OPT_MAX_SECT: 3657aef9ec39SRoland Dreier if (match_int(args, &token)) { 3658e0bda7d8SBart Van Assche pr_warn("bad max sect parameter '%s'\n", p); 3659aef9ec39SRoland Dreier goto out; 3660aef9ec39SRoland Dreier } 3661aef9ec39SRoland Dreier target->scsi_host->max_sectors = token; 3662aef9ec39SRoland Dreier break; 3663aef9ec39SRoland Dreier 36644d73f95fSBart Van Assche case SRP_OPT_QUEUE_SIZE: 36654d73f95fSBart Van Assche if (match_int(args, &token) || token < 1) { 36664d73f95fSBart Van Assche pr_warn("bad queue_size parameter '%s'\n", p); 36674d73f95fSBart Van Assche goto out; 36684d73f95fSBart Van Assche } 36694d73f95fSBart Van Assche target->scsi_host->can_queue = token; 36704d73f95fSBart Van Assche target->queue_size = token + SRP_RSP_SQ_SIZE + 36714d73f95fSBart Van Assche SRP_TSK_MGMT_SQ_SIZE; 36724d73f95fSBart Van Assche if (!(opt_mask & SRP_OPT_MAX_CMD_PER_LUN)) 36734d73f95fSBart Van Assche target->scsi_host->cmd_per_lun = token; 36744d73f95fSBart Van Assche break; 36754d73f95fSBart Van Assche 367652fb2b50SVu Pham case SRP_OPT_MAX_CMD_PER_LUN: 36774d73f95fSBart Van Assche if (match_int(args, &token) || token < 1) { 3678e0bda7d8SBart Van Assche pr_warn("bad max cmd_per_lun parameter '%s'\n", 3679e0bda7d8SBart Van Assche p); 368052fb2b50SVu Pham goto out; 368152fb2b50SVu Pham } 36824d73f95fSBart Van Assche target->scsi_host->cmd_per_lun = token; 368352fb2b50SVu Pham break; 368452fb2b50SVu Pham 3685b0780ee5SBart Van Assche case SRP_OPT_TARGET_CAN_QUEUE: 3686b0780ee5SBart Van Assche if (match_int(args, &token) || token < 1) { 3687b0780ee5SBart Van Assche pr_warn("bad max target_can_queue parameter '%s'\n", 3688b0780ee5SBart Van Assche p); 3689b0780ee5SBart Van Assche goto out; 3690b0780ee5SBart Van Assche } 3691b0780ee5SBart Van Assche target->target_can_queue = token; 3692b0780ee5SBart Van Assche break; 3693b0780ee5SBart Van Assche 36940c0450dbSRamachandra K case SRP_OPT_IO_CLASS: 36950c0450dbSRamachandra K if (match_hex(args, &token)) { 3696e0bda7d8SBart Van Assche pr_warn("bad IO class parameter '%s'\n", p); 36970c0450dbSRamachandra K goto out; 36980c0450dbSRamachandra K } 36990c0450dbSRamachandra K if (token != SRP_REV10_IB_IO_CLASS && 37000c0450dbSRamachandra K token != SRP_REV16A_IB_IO_CLASS) { 3701e0bda7d8SBart Van Assche pr_warn("unknown IO class parameter value %x specified (use %x or %x).\n", 3702e0bda7d8SBart Van Assche token, SRP_REV10_IB_IO_CLASS, 3703e0bda7d8SBart Van Assche SRP_REV16A_IB_IO_CLASS); 37040c0450dbSRamachandra K goto out; 37050c0450dbSRamachandra K } 37060c0450dbSRamachandra K target->io_class = token; 37070c0450dbSRamachandra K break; 37080c0450dbSRamachandra K 370901cb9bcbSIshai Rabinovitz case SRP_OPT_INITIATOR_EXT: 371001cb9bcbSIshai Rabinovitz p = match_strdup(args); 3711a20f3a6dSIshai Rabinovitz if (!p) { 3712a20f3a6dSIshai Rabinovitz ret = -ENOMEM; 3713a20f3a6dSIshai Rabinovitz goto out; 3714a20f3a6dSIshai Rabinovitz } 37152a174df0SBart Van Assche ret = kstrtoull(p, 16, &ull); 37162a174df0SBart Van Assche if (ret) { 37172a174df0SBart Van Assche pr_warn("bad initiator_ext value '%s'\n", p); 37182a174df0SBart Van Assche kfree(p); 37192a174df0SBart Van Assche goto out; 37202a174df0SBart Van Assche } 37212a174df0SBart Van Assche target->initiator_ext = cpu_to_be64(ull); 372201cb9bcbSIshai Rabinovitz kfree(p); 372301cb9bcbSIshai Rabinovitz break; 372401cb9bcbSIshai Rabinovitz 372549248644SDavid Dillow case SRP_OPT_CMD_SG_ENTRIES: 372649248644SDavid Dillow if (match_int(args, &token) || token < 1 || token > 255) { 3727e0bda7d8SBart Van Assche pr_warn("bad max cmd_sg_entries parameter '%s'\n", 3728e0bda7d8SBart Van Assche p); 372949248644SDavid Dillow goto out; 373049248644SDavid Dillow } 373149248644SDavid Dillow target->cmd_sg_cnt = token; 373249248644SDavid Dillow break; 373349248644SDavid Dillow 3734c07d424dSDavid Dillow case SRP_OPT_ALLOW_EXT_SG: 3735c07d424dSDavid Dillow if (match_int(args, &token)) { 3736e0bda7d8SBart Van Assche pr_warn("bad allow_ext_sg parameter '%s'\n", p); 3737c07d424dSDavid Dillow goto out; 3738c07d424dSDavid Dillow } 3739c07d424dSDavid Dillow target->allow_ext_sg = !!token; 3740c07d424dSDavid Dillow break; 3741c07d424dSDavid Dillow 3742c07d424dSDavid Dillow case SRP_OPT_SG_TABLESIZE: 3743c07d424dSDavid Dillow if (match_int(args, &token) || token < 1 || 374465e8617fSMing Lin token > SG_MAX_SEGMENTS) { 3745e0bda7d8SBart Van Assche pr_warn("bad max sg_tablesize parameter '%s'\n", 3746e0bda7d8SBart Van Assche p); 3747c07d424dSDavid Dillow goto out; 3748c07d424dSDavid Dillow } 3749c07d424dSDavid Dillow target->sg_tablesize = token; 3750c07d424dSDavid Dillow break; 3751c07d424dSDavid Dillow 37524b5e5f41SBart Van Assche case SRP_OPT_COMP_VECTOR: 37534b5e5f41SBart Van Assche if (match_int(args, &token) || token < 0) { 37544b5e5f41SBart Van Assche pr_warn("bad comp_vector parameter '%s'\n", p); 37554b5e5f41SBart Van Assche goto out; 37564b5e5f41SBart Van Assche } 37574b5e5f41SBart Van Assche target->comp_vector = token; 37584b5e5f41SBart Van Assche break; 37594b5e5f41SBart Van Assche 37607bb312e4SVu Pham case SRP_OPT_TL_RETRY_COUNT: 37617bb312e4SVu Pham if (match_int(args, &token) || token < 2 || token > 7) { 37627bb312e4SVu Pham pr_warn("bad tl_retry_count parameter '%s' (must be a number between 2 and 7)\n", 37637bb312e4SVu Pham p); 37647bb312e4SVu Pham goto out; 37657bb312e4SVu Pham } 37667bb312e4SVu Pham target->tl_retry_count = token; 37677bb312e4SVu Pham break; 37687bb312e4SVu Pham 3769aef9ec39SRoland Dreier default: 3770e0bda7d8SBart Van Assche pr_warn("unknown parameter or missing value '%s' in target creation request\n", 3771e0bda7d8SBart Van Assche p); 3772aef9ec39SRoland Dreier goto out; 3773aef9ec39SRoland Dreier } 3774aef9ec39SRoland Dreier } 3775aef9ec39SRoland Dreier 377619f31343SBart Van Assche for (i = 0; i < ARRAY_SIZE(srp_opt_mandatory); i++) { 377719f31343SBart Van Assche if ((opt_mask & srp_opt_mandatory[i]) == srp_opt_mandatory[i]) { 3778aef9ec39SRoland Dreier ret = 0; 377919f31343SBart Van Assche break; 378019f31343SBart Van Assche } 378119f31343SBart Van Assche } 378219f31343SBart Van Assche if (ret) 378319f31343SBart Van Assche pr_warn("target creation request is missing one or more parameters\n"); 3784aef9ec39SRoland Dreier 37854d73f95fSBart Van Assche if (target->scsi_host->cmd_per_lun > target->scsi_host->can_queue 37864d73f95fSBart Van Assche && (opt_mask & SRP_OPT_MAX_CMD_PER_LUN)) 37874d73f95fSBart Van Assche pr_warn("cmd_per_lun = %d > queue_size = %d\n", 37884d73f95fSBart Van Assche target->scsi_host->cmd_per_lun, 37894d73f95fSBart Van Assche target->scsi_host->can_queue); 37904d73f95fSBart Van Assche 3791aef9ec39SRoland Dreier out: 3792aef9ec39SRoland Dreier kfree(options); 3793aef9ec39SRoland Dreier return ret; 3794aef9ec39SRoland Dreier } 3795aef9ec39SRoland Dreier 3796ee959b00STony Jones static ssize_t srp_create_target(struct device *dev, 3797ee959b00STony Jones struct device_attribute *attr, 3798aef9ec39SRoland Dreier const char *buf, size_t count) 3799aef9ec39SRoland Dreier { 3800aef9ec39SRoland Dreier struct srp_host *host = 3801ee959b00STony Jones container_of(dev, struct srp_host, dev); 3802aef9ec39SRoland Dreier struct Scsi_Host *target_host; 3803aef9ec39SRoland Dreier struct srp_target_port *target; 3804509c07bcSBart Van Assche struct srp_rdma_ch *ch; 3805d1b4289eSBart Van Assche struct srp_device *srp_dev = host->srp_dev; 3806d1b4289eSBart Van Assche struct ib_device *ibdev = srp_dev->dev; 3807d92c0da7SBart Van Assche int ret, node_idx, node, cpu, i; 3808509c5f33SBart Van Assche unsigned int max_sectors_per_mr, mr_per_cmd = 0; 3809d92c0da7SBart Van Assche bool multich = false; 3810513d5647SBart Van Assche uint32_t max_iu_len; 3811aef9ec39SRoland Dreier 3812aef9ec39SRoland Dreier target_host = scsi_host_alloc(&srp_template, 3813aef9ec39SRoland Dreier sizeof (struct srp_target_port)); 3814aef9ec39SRoland Dreier if (!target_host) 3815aef9ec39SRoland Dreier return -ENOMEM; 3816aef9ec39SRoland Dreier 38173236822bSFUJITA Tomonori target_host->transportt = ib_srp_transport_template; 3818fd1b6c4aSBart Van Assche target_host->max_channel = 0; 3819fd1b6c4aSBart Van Assche target_host->max_id = 1; 3820985aa495SBart Van Assche target_host->max_lun = -1LL; 38213c8edf0eSArne Redlich target_host->max_cmd_len = sizeof ((struct srp_cmd *) (void *) 0L)->cdb; 38220b5cb330SBart Van Assche target_host->max_segment_size = ib_dma_max_seg_size(ibdev); 38235f068992SRoland Dreier 3824aef9ec39SRoland Dreier target = host_to_target(target_host); 3825aef9ec39SRoland Dreier 382619f31343SBart Van Assche target->net = kobj_ns_grab_current(KOBJ_NS_TYPE_NET); 38270c0450dbSRamachandra K target->io_class = SRP_REV16A_IB_IO_CLASS; 3828aef9ec39SRoland Dreier target->scsi_host = target_host; 3829aef9ec39SRoland Dreier target->srp_host = host; 3830e6bf5f48SJason Gunthorpe target->lkey = host->srp_dev->pd->local_dma_lkey; 3831cee687b6SBart Van Assche target->global_rkey = host->srp_dev->global_rkey; 383249248644SDavid Dillow target->cmd_sg_cnt = cmd_sg_entries; 3833c07d424dSDavid Dillow target->sg_tablesize = indirect_sg_entries ? : cmd_sg_entries; 3834c07d424dSDavid Dillow target->allow_ext_sg = allow_ext_sg; 38357bb312e4SVu Pham target->tl_retry_count = 7; 38364d73f95fSBart Van Assche target->queue_size = SRP_DEFAULT_QUEUE_SIZE; 3837aef9ec39SRoland Dreier 383834aa654eSBart Van Assche /* 383934aa654eSBart Van Assche * Avoid that the SCSI host can be removed by srp_remove_target() 384034aa654eSBart Van Assche * before this function returns. 384134aa654eSBart Van Assche */ 384234aa654eSBart Van Assche scsi_host_get(target->scsi_host); 384334aa654eSBart Van Assche 38444fa354c9SBart Van Assche ret = mutex_lock_interruptible(&host->add_target_mutex); 38454fa354c9SBart Van Assche if (ret < 0) 38464fa354c9SBart Van Assche goto put; 38472d7091bcSBart Van Assche 384819f31343SBart Van Assche ret = srp_parse_options(target->net, buf, target); 3849aef9ec39SRoland Dreier if (ret) 3850fb49c8bbSBart Van Assche goto out; 3851aef9ec39SRoland Dreier 38524d73f95fSBart Van Assche target->req_ring_size = target->queue_size - SRP_TSK_MGMT_SQ_SIZE; 38534d73f95fSBart Van Assche 385496fc248aSBart Van Assche if (!srp_conn_unique(target->srp_host, target)) { 385519f31343SBart Van Assche if (target->using_rdma_cm) { 385619f31343SBart Van Assche shost_printk(KERN_INFO, target->scsi_host, 38577da09af9SBart Van Assche PFX "Already connected to target port with id_ext=%016llx;ioc_guid=%016llx;dest=%pIS\n", 385819f31343SBart Van Assche be64_to_cpu(target->id_ext), 385919f31343SBart Van Assche be64_to_cpu(target->ioc_guid), 38607da09af9SBart Van Assche &target->rdma_cm.dst); 386119f31343SBart Van Assche } else { 386296fc248aSBart Van Assche shost_printk(KERN_INFO, target->scsi_host, 386396fc248aSBart Van Assche PFX "Already connected to target port with id_ext=%016llx;ioc_guid=%016llx;initiator_ext=%016llx\n", 386496fc248aSBart Van Assche be64_to_cpu(target->id_ext), 386596fc248aSBart Van Assche be64_to_cpu(target->ioc_guid), 386696fc248aSBart Van Assche be64_to_cpu(target->initiator_ext)); 386719f31343SBart Van Assche } 386896fc248aSBart Van Assche ret = -EEXIST; 3869fb49c8bbSBart Van Assche goto out; 387096fc248aSBart Van Assche } 387196fc248aSBart Van Assche 38725cfb1782SBart Van Assche if (!srp_dev->has_fmr && !srp_dev->has_fr && !target->allow_ext_sg && 3873c07d424dSDavid Dillow target->cmd_sg_cnt < target->sg_tablesize) { 38745cfb1782SBart Van Assche pr_warn("No MR pool and no external indirect descriptors, limiting sg_tablesize to cmd_sg_cnt\n"); 3875c07d424dSDavid Dillow target->sg_tablesize = target->cmd_sg_cnt; 3876c07d424dSDavid Dillow } 3877c07d424dSDavid Dillow 3878509c5f33SBart Van Assche if (srp_dev->use_fast_reg || srp_dev->use_fmr) { 3879fbd36818SSergey Gorenko bool gaps_reg = (ibdev->attrs.device_cap_flags & 3880fbd36818SSergey Gorenko IB_DEVICE_SG_GAPS_REG); 3881fbd36818SSergey Gorenko 3882509c5f33SBart Van Assche max_sectors_per_mr = srp_dev->max_pages_per_mr << 3883509c5f33SBart Van Assche (ilog2(srp_dev->mr_page_size) - 9); 3884fbd36818SSergey Gorenko if (!gaps_reg) { 3885fbd36818SSergey Gorenko /* 3886fbd36818SSergey Gorenko * FR and FMR can only map one HCA page per entry. If 3887fbd36818SSergey Gorenko * the start address is not aligned on a HCA page 3888fbd36818SSergey Gorenko * boundary two entries will be used for the head and 3889fbd36818SSergey Gorenko * the tail although these two entries combined 3890fbd36818SSergey Gorenko * contain at most one HCA page of data. Hence the "+ 3891fbd36818SSergey Gorenko * 1" in the calculation below. 3892fbd36818SSergey Gorenko * 3893fbd36818SSergey Gorenko * The indirect data buffer descriptor is contiguous 3894fbd36818SSergey Gorenko * so the memory for that buffer will only be 3895fbd36818SSergey Gorenko * registered if register_always is true. Hence add 3896fbd36818SSergey Gorenko * one to mr_per_cmd if register_always has been set. 3897fbd36818SSergey Gorenko */ 3898509c5f33SBart Van Assche mr_per_cmd = register_always + 3899509c5f33SBart Van Assche (target->scsi_host->max_sectors + 1 + 3900509c5f33SBart Van Assche max_sectors_per_mr - 1) / max_sectors_per_mr; 3901fbd36818SSergey Gorenko } else { 3902fbd36818SSergey Gorenko mr_per_cmd = register_always + 3903fbd36818SSergey Gorenko (target->sg_tablesize + 3904fbd36818SSergey Gorenko srp_dev->max_pages_per_mr - 1) / 3905fbd36818SSergey Gorenko srp_dev->max_pages_per_mr; 3906fbd36818SSergey Gorenko } 3907509c5f33SBart Van Assche pr_debug("max_sectors = %u; max_pages_per_mr = %u; mr_page_size = %u; max_sectors_per_mr = %u; mr_per_cmd = %u\n", 3908fbd36818SSergey Gorenko target->scsi_host->max_sectors, srp_dev->max_pages_per_mr, srp_dev->mr_page_size, 3909509c5f33SBart Van Assche max_sectors_per_mr, mr_per_cmd); 3910509c5f33SBart Van Assche } 3911509c5f33SBart Van Assche 3912c07d424dSDavid Dillow target_host->sg_tablesize = target->sg_tablesize; 3913509c5f33SBart Van Assche target->mr_pool_size = target->scsi_host->can_queue * mr_per_cmd; 3914509c5f33SBart Van Assche target->mr_per_cmd = mr_per_cmd; 3915c07d424dSDavid Dillow target->indirect_size = target->sg_tablesize * 3916c07d424dSDavid Dillow sizeof (struct srp_direct_buf); 3917882981f4SBart Van Assche max_iu_len = srp_max_it_iu_len(target->cmd_sg_cnt, srp_use_imm_data); 391849248644SDavid Dillow 3919c1120f89SBart Van Assche INIT_WORK(&target->tl_err_work, srp_tl_err_work); 3920ef6c49d8SBart Van Assche INIT_WORK(&target->remove_work, srp_remove_work); 39218f26c9ffSDavid Dillow spin_lock_init(&target->lock); 39221dfce294SParav Pandit ret = rdma_query_gid(ibdev, host->port, 0, &target->sgid); 39232088ca66SSagi Grimberg if (ret) 3924fb49c8bbSBart Van Assche goto out; 3925d92c0da7SBart Van Assche 3926d92c0da7SBart Van Assche ret = -ENOMEM; 3927d92c0da7SBart Van Assche target->ch_count = max_t(unsigned, num_online_nodes(), 3928d92c0da7SBart Van Assche min(ch_count ? : 3929d92c0da7SBart Van Assche min(4 * num_online_nodes(), 3930d92c0da7SBart Van Assche ibdev->num_comp_vectors), 3931d92c0da7SBart Van Assche num_online_cpus())); 3932d92c0da7SBart Van Assche target->ch = kcalloc(target->ch_count, sizeof(*target->ch), 3933d92c0da7SBart Van Assche GFP_KERNEL); 3934d92c0da7SBart Van Assche if (!target->ch) 3935fb49c8bbSBart Van Assche goto out; 3936d92c0da7SBart Van Assche 3937d92c0da7SBart Van Assche node_idx = 0; 3938d92c0da7SBart Van Assche for_each_online_node(node) { 3939d92c0da7SBart Van Assche const int ch_start = (node_idx * target->ch_count / 3940d92c0da7SBart Van Assche num_online_nodes()); 3941d92c0da7SBart Van Assche const int ch_end = ((node_idx + 1) * target->ch_count / 3942d92c0da7SBart Van Assche num_online_nodes()); 39433a148896SBart Van Assche const int cv_start = node_idx * ibdev->num_comp_vectors / 39443a148896SBart Van Assche num_online_nodes(); 39453a148896SBart Van Assche const int cv_end = (node_idx + 1) * ibdev->num_comp_vectors / 39463a148896SBart Van Assche num_online_nodes(); 3947d92c0da7SBart Van Assche int cpu_idx = 0; 3948d92c0da7SBart Van Assche 3949d92c0da7SBart Van Assche for_each_online_cpu(cpu) { 3950d92c0da7SBart Van Assche if (cpu_to_node(cpu) != node) 3951d92c0da7SBart Van Assche continue; 3952d92c0da7SBart Van Assche if (ch_start + cpu_idx >= ch_end) 3953d92c0da7SBart Van Assche continue; 3954d92c0da7SBart Van Assche ch = &target->ch[ch_start + cpu_idx]; 3955d92c0da7SBart Van Assche ch->target = target; 3956d92c0da7SBart Van Assche ch->comp_vector = cv_start == cv_end ? cv_start : 3957d92c0da7SBart Van Assche cv_start + cpu_idx % (cv_end - cv_start); 3958d92c0da7SBart Van Assche spin_lock_init(&ch->lock); 3959d92c0da7SBart Van Assche INIT_LIST_HEAD(&ch->free_tx); 3960d92c0da7SBart Van Assche ret = srp_new_cm_id(ch); 3961d92c0da7SBart Van Assche if (ret) 3962d92c0da7SBart Van Assche goto err_disconnect; 3963aef9ec39SRoland Dreier 3964509c07bcSBart Van Assche ret = srp_create_ch_ib(ch); 3965aef9ec39SRoland Dreier if (ret) 3966d92c0da7SBart Van Assche goto err_disconnect; 3967aef9ec39SRoland Dreier 3968d92c0da7SBart Van Assche ret = srp_alloc_req_data(ch); 39699fe4bcf4SDavid Dillow if (ret) 3970d92c0da7SBart Van Assche goto err_disconnect; 3971aef9ec39SRoland Dreier 3972513d5647SBart Van Assche ret = srp_connect_ch(ch, max_iu_len, multich); 3973aef9ec39SRoland Dreier if (ret) { 397419f31343SBart Van Assche char dst[64]; 397519f31343SBart Van Assche 397619f31343SBart Van Assche if (target->using_rdma_cm) 39777da09af9SBart Van Assche snprintf(dst, sizeof(dst), "%pIS", 39787da09af9SBart Van Assche &target->rdma_cm.dst); 397919f31343SBart Van Assche else 398019f31343SBart Van Assche snprintf(dst, sizeof(dst), "%pI6", 398119f31343SBart Van Assche target->ib_cm.orig_dgid.raw); 39827aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 398319f31343SBart Van Assche PFX "Connection %d/%d to %s failed\n", 3984d92c0da7SBart Van Assche ch_start + cpu_idx, 398519f31343SBart Van Assche target->ch_count, dst); 3986d92c0da7SBart Van Assche if (node_idx == 0 && cpu_idx == 0) { 3987b02c1536SBart Van Assche goto free_ch; 3988d92c0da7SBart Van Assche } else { 3989d92c0da7SBart Van Assche srp_free_ch_ib(target, ch); 3990d92c0da7SBart Van Assche srp_free_req_data(target, ch); 3991d92c0da7SBart Van Assche target->ch_count = ch - target->ch; 3992c257ea6fSBart Van Assche goto connected; 3993aef9ec39SRoland Dreier } 3994d92c0da7SBart Van Assche } 3995d92c0da7SBart Van Assche 3996d92c0da7SBart Van Assche multich = true; 3997d92c0da7SBart Van Assche cpu_idx++; 3998d92c0da7SBart Van Assche } 3999d92c0da7SBart Van Assche node_idx++; 4000d92c0da7SBart Van Assche } 4001d92c0da7SBart Van Assche 4002c257ea6fSBart Van Assche connected: 4003d92c0da7SBart Van Assche target->scsi_host->nr_hw_queues = target->ch_count; 4004aef9ec39SRoland Dreier 4005aef9ec39SRoland Dreier ret = srp_add_target(host, target); 4006aef9ec39SRoland Dreier if (ret) 4007aef9ec39SRoland Dreier goto err_disconnect; 4008aef9ec39SRoland Dreier 400934aa654eSBart Van Assche if (target->state != SRP_TARGET_REMOVED) { 401019f31343SBart Van Assche if (target->using_rdma_cm) { 401119f31343SBart Van Assche shost_printk(KERN_DEBUG, target->scsi_host, PFX 40127da09af9SBart Van Assche "new target: id_ext %016llx ioc_guid %016llx sgid %pI6 dest %pIS\n", 401319f31343SBart Van Assche be64_to_cpu(target->id_ext), 401419f31343SBart Van Assche be64_to_cpu(target->ioc_guid), 40157da09af9SBart Van Assche target->sgid.raw, &target->rdma_cm.dst); 401619f31343SBart Van Assche } else { 4017e7ffde01SBart Van Assche shost_printk(KERN_DEBUG, target->scsi_host, PFX 4018e7ffde01SBart Van Assche "new target: id_ext %016llx ioc_guid %016llx pkey %04x service_id %016llx sgid %pI6 dgid %pI6\n", 4019e7ffde01SBart Van Assche be64_to_cpu(target->id_ext), 4020e7ffde01SBart Van Assche be64_to_cpu(target->ioc_guid), 402119f31343SBart Van Assche be16_to_cpu(target->ib_cm.pkey), 402219f31343SBart Van Assche be64_to_cpu(target->ib_cm.service_id), 402319f31343SBart Van Assche target->sgid.raw, 402419f31343SBart Van Assche target->ib_cm.orig_dgid.raw); 402519f31343SBart Van Assche } 402634aa654eSBart Van Assche } 4027e7ffde01SBart Van Assche 40282d7091bcSBart Van Assche ret = count; 40292d7091bcSBart Van Assche 40302d7091bcSBart Van Assche out: 40312d7091bcSBart Van Assche mutex_unlock(&host->add_target_mutex); 403234aa654eSBart Van Assche 40334fa354c9SBart Van Assche put: 403434aa654eSBart Van Assche scsi_host_put(target->scsi_host); 403519f31343SBart Van Assche if (ret < 0) { 403619f31343SBart Van Assche /* 403719f31343SBart Van Assche * If a call to srp_remove_target() has not been scheduled, 403819f31343SBart Van Assche * drop the network namespace reference now that was obtained 403919f31343SBart Van Assche * earlier in this function. 404019f31343SBart Van Assche */ 404119f31343SBart Van Assche if (target->state != SRP_TARGET_REMOVED) 404219f31343SBart Van Assche kobj_ns_drop(KOBJ_NS_TYPE_NET, target->net); 4043bc44bd1dSBart Van Assche scsi_host_put(target->scsi_host); 404419f31343SBart Van Assche } 404534aa654eSBart Van Assche 40462d7091bcSBart Van Assche return ret; 4047aef9ec39SRoland Dreier 4048aef9ec39SRoland Dreier err_disconnect: 4049aef9ec39SRoland Dreier srp_disconnect_target(target); 4050aef9ec39SRoland Dreier 4051b02c1536SBart Van Assche free_ch: 4052d92c0da7SBart Van Assche for (i = 0; i < target->ch_count; i++) { 4053d92c0da7SBart Van Assche ch = &target->ch[i]; 4054509c07bcSBart Van Assche srp_free_ch_ib(target, ch); 4055509c07bcSBart Van Assche srp_free_req_data(target, ch); 4056d92c0da7SBart Van Assche } 4057d92c0da7SBart Van Assche 4058d92c0da7SBart Van Assche kfree(target->ch); 40592d7091bcSBart Van Assche goto out; 4060aef9ec39SRoland Dreier } 4061aef9ec39SRoland Dreier 4062ee959b00STony Jones static DEVICE_ATTR(add_target, S_IWUSR, NULL, srp_create_target); 4063aef9ec39SRoland Dreier 4064ee959b00STony Jones static ssize_t show_ibdev(struct device *dev, struct device_attribute *attr, 4065ee959b00STony Jones char *buf) 4066aef9ec39SRoland Dreier { 4067ee959b00STony Jones struct srp_host *host = container_of(dev, struct srp_host, dev); 4068aef9ec39SRoland Dreier 40696c854111SJason Gunthorpe return sprintf(buf, "%s\n", dev_name(&host->srp_dev->dev->dev)); 4070aef9ec39SRoland Dreier } 4071aef9ec39SRoland Dreier 4072ee959b00STony Jones static DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL); 4073aef9ec39SRoland Dreier 4074ee959b00STony Jones static ssize_t show_port(struct device *dev, struct device_attribute *attr, 4075ee959b00STony Jones char *buf) 4076aef9ec39SRoland Dreier { 4077ee959b00STony Jones struct srp_host *host = container_of(dev, struct srp_host, dev); 4078aef9ec39SRoland Dreier 4079aef9ec39SRoland Dreier return sprintf(buf, "%d\n", host->port); 4080aef9ec39SRoland Dreier } 4081aef9ec39SRoland Dreier 4082ee959b00STony Jones static DEVICE_ATTR(port, S_IRUGO, show_port, NULL); 4083aef9ec39SRoland Dreier 4084f5358a17SRoland Dreier static struct srp_host *srp_add_port(struct srp_device *device, u8 port) 4085aef9ec39SRoland Dreier { 4086aef9ec39SRoland Dreier struct srp_host *host; 4087aef9ec39SRoland Dreier 4088aef9ec39SRoland Dreier host = kzalloc(sizeof *host, GFP_KERNEL); 4089aef9ec39SRoland Dreier if (!host) 4090aef9ec39SRoland Dreier return NULL; 4091aef9ec39SRoland Dreier 4092aef9ec39SRoland Dreier INIT_LIST_HEAD(&host->target_list); 4093b3589fd4SMatthew Wilcox spin_lock_init(&host->target_lock); 4094aef9ec39SRoland Dreier init_completion(&host->released); 40952d7091bcSBart Van Assche mutex_init(&host->add_target_mutex); 409605321937SGreg Kroah-Hartman host->srp_dev = device; 4097aef9ec39SRoland Dreier host->port = port; 4098aef9ec39SRoland Dreier 4099ee959b00STony Jones host->dev.class = &srp_class; 4100dee2b82aSBart Van Assche host->dev.parent = device->dev->dev.parent; 41016c854111SJason Gunthorpe dev_set_name(&host->dev, "srp-%s-%d", dev_name(&device->dev->dev), 41026c854111SJason Gunthorpe port); 4103aef9ec39SRoland Dreier 4104ee959b00STony Jones if (device_register(&host->dev)) 4105f5358a17SRoland Dreier goto free_host; 4106ee959b00STony Jones if (device_create_file(&host->dev, &dev_attr_add_target)) 4107aef9ec39SRoland Dreier goto err_class; 4108ee959b00STony Jones if (device_create_file(&host->dev, &dev_attr_ibdev)) 4109aef9ec39SRoland Dreier goto err_class; 4110ee959b00STony Jones if (device_create_file(&host->dev, &dev_attr_port)) 4111aef9ec39SRoland Dreier goto err_class; 4112aef9ec39SRoland Dreier 4113aef9ec39SRoland Dreier return host; 4114aef9ec39SRoland Dreier 4115aef9ec39SRoland Dreier err_class: 4116ee959b00STony Jones device_unregister(&host->dev); 4117aef9ec39SRoland Dreier 4118f5358a17SRoland Dreier free_host: 4119aef9ec39SRoland Dreier kfree(host); 4120aef9ec39SRoland Dreier 4121aef9ec39SRoland Dreier return NULL; 4122aef9ec39SRoland Dreier } 4123aef9ec39SRoland Dreier 4124aef9ec39SRoland Dreier static void srp_add_one(struct ib_device *device) 4125aef9ec39SRoland Dreier { 4126f5358a17SRoland Dreier struct srp_device *srp_dev; 4127042dd765SBart Van Assche struct ib_device_attr *attr = &device->attrs; 4128aef9ec39SRoland Dreier struct srp_host *host; 4129ea1075edSJason Gunthorpe int mr_page_shift; 4130ea1075edSJason Gunthorpe unsigned int p; 413152ede08fSBart Van Assche u64 max_pages_per_mr; 41325f071777SChristoph Hellwig unsigned int flags = 0; 4133aef9ec39SRoland Dreier 4134249f0656SBart Van Assche srp_dev = kzalloc(sizeof(*srp_dev), GFP_KERNEL); 4135f5358a17SRoland Dreier if (!srp_dev) 41364a061b28SOr Gerlitz return; 4137f5358a17SRoland Dreier 4138f5358a17SRoland Dreier /* 4139f5358a17SRoland Dreier * Use the smallest page size supported by the HCA, down to a 41408f26c9ffSDavid Dillow * minimum of 4096 bytes. We're unlikely to build large sglists 41418f26c9ffSDavid Dillow * out of smaller entries. 4142f5358a17SRoland Dreier */ 4143042dd765SBart Van Assche mr_page_shift = max(12, ffs(attr->page_size_cap) - 1); 414452ede08fSBart Van Assche srp_dev->mr_page_size = 1 << mr_page_shift; 414552ede08fSBart Van Assche srp_dev->mr_page_mask = ~((u64) srp_dev->mr_page_size - 1); 4146042dd765SBart Van Assche max_pages_per_mr = attr->max_mr_size; 414752ede08fSBart Van Assche do_div(max_pages_per_mr, srp_dev->mr_page_size); 4148509c5f33SBart Van Assche pr_debug("%s: %llu / %u = %llu <> %u\n", __func__, 4149042dd765SBart Van Assche attr->max_mr_size, srp_dev->mr_page_size, 4150509c5f33SBart Van Assche max_pages_per_mr, SRP_MAX_PAGES_PER_MR); 415152ede08fSBart Van Assche srp_dev->max_pages_per_mr = min_t(u64, SRP_MAX_PAGES_PER_MR, 415252ede08fSBart Van Assche max_pages_per_mr); 4153835ee624SBart Van Assche 41543023a1e9SKamal Heib srp_dev->has_fmr = (device->ops.alloc_fmr && 41553023a1e9SKamal Heib device->ops.dealloc_fmr && 41563023a1e9SKamal Heib device->ops.map_phys_fmr && 41573023a1e9SKamal Heib device->ops.unmap_fmr); 4158042dd765SBart Van Assche srp_dev->has_fr = (attr->device_cap_flags & 4159835ee624SBart Van Assche IB_DEVICE_MEM_MGT_EXTENSIONS); 4160c222a39fSBart Van Assche if (!never_register && !srp_dev->has_fmr && !srp_dev->has_fr) { 4161835ee624SBart Van Assche dev_warn(&device->dev, "neither FMR nor FR is supported\n"); 4162c222a39fSBart Van Assche } else if (!never_register && 4163042dd765SBart Van Assche attr->max_mr_size >= 2 * srp_dev->mr_page_size) { 4164835ee624SBart Van Assche srp_dev->use_fast_reg = (srp_dev->has_fr && 4165835ee624SBart Van Assche (!srp_dev->has_fmr || prefer_fr)); 4166835ee624SBart Van Assche srp_dev->use_fmr = !srp_dev->use_fast_reg && srp_dev->has_fmr; 4167509c5f33SBart Van Assche } 4168835ee624SBart Van Assche 41695f071777SChristoph Hellwig if (never_register || !register_always || 41705f071777SChristoph Hellwig (!srp_dev->has_fmr && !srp_dev->has_fr)) 41715f071777SChristoph Hellwig flags |= IB_PD_UNSAFE_GLOBAL_RKEY; 41725f071777SChristoph Hellwig 41735cfb1782SBart Van Assche if (srp_dev->use_fast_reg) { 41745cfb1782SBart Van Assche srp_dev->max_pages_per_mr = 41755cfb1782SBart Van Assche min_t(u32, srp_dev->max_pages_per_mr, 4176042dd765SBart Van Assche attr->max_fast_reg_page_list_len); 41775cfb1782SBart Van Assche } 417852ede08fSBart Van Assche srp_dev->mr_max_size = srp_dev->mr_page_size * 417952ede08fSBart Van Assche srp_dev->max_pages_per_mr; 41804a061b28SOr Gerlitz 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", 41816c854111SJason Gunthorpe dev_name(&device->dev), mr_page_shift, attr->max_mr_size, 4182042dd765SBart Van Assche attr->max_fast_reg_page_list_len, 418352ede08fSBart Van Assche srp_dev->max_pages_per_mr, srp_dev->mr_max_size); 4184f5358a17SRoland Dreier 4185f5358a17SRoland Dreier INIT_LIST_HEAD(&srp_dev->dev_list); 4186f5358a17SRoland Dreier 4187f5358a17SRoland Dreier srp_dev->dev = device; 41885f071777SChristoph Hellwig srp_dev->pd = ib_alloc_pd(device, flags); 4189f5358a17SRoland Dreier if (IS_ERR(srp_dev->pd)) 4190f5358a17SRoland Dreier goto free_dev; 4191f5358a17SRoland Dreier 4192cee687b6SBart Van Assche if (flags & IB_PD_UNSAFE_GLOBAL_RKEY) { 4193cee687b6SBart Van Assche srp_dev->global_rkey = srp_dev->pd->unsafe_global_rkey; 4194cee687b6SBart Van Assche WARN_ON_ONCE(srp_dev->global_rkey == 0); 4195cee687b6SBart Van Assche } 4196f5358a17SRoland Dreier 4197ea1075edSJason Gunthorpe rdma_for_each_port (device, p) { 4198f5358a17SRoland Dreier host = srp_add_port(srp_dev, p); 4199aef9ec39SRoland Dreier if (host) 4200f5358a17SRoland Dreier list_add_tail(&host->list, &srp_dev->dev_list); 4201aef9ec39SRoland Dreier } 4202aef9ec39SRoland Dreier 4203f5358a17SRoland Dreier ib_set_client_data(device, &srp_client, srp_dev); 42044a061b28SOr Gerlitz return; 4205f5358a17SRoland Dreier 4206f5358a17SRoland Dreier free_dev: 4207f5358a17SRoland Dreier kfree(srp_dev); 4208aef9ec39SRoland Dreier } 4209aef9ec39SRoland Dreier 42107c1eb45aSHaggai Eran static void srp_remove_one(struct ib_device *device, void *client_data) 4211aef9ec39SRoland Dreier { 4212f5358a17SRoland Dreier struct srp_device *srp_dev; 4213aef9ec39SRoland Dreier struct srp_host *host, *tmp_host; 4214ef6c49d8SBart Van Assche struct srp_target_port *target; 4215aef9ec39SRoland Dreier 42167c1eb45aSHaggai Eran srp_dev = client_data; 42171fe0cb84SDotan Barak if (!srp_dev) 42181fe0cb84SDotan Barak return; 4219aef9ec39SRoland Dreier 4220f5358a17SRoland Dreier list_for_each_entry_safe(host, tmp_host, &srp_dev->dev_list, list) { 4221ee959b00STony Jones device_unregister(&host->dev); 4222aef9ec39SRoland Dreier /* 4223aef9ec39SRoland Dreier * Wait for the sysfs entry to go away, so that no new 4224aef9ec39SRoland Dreier * target ports can be created. 4225aef9ec39SRoland Dreier */ 4226aef9ec39SRoland Dreier wait_for_completion(&host->released); 4227aef9ec39SRoland Dreier 4228aef9ec39SRoland Dreier /* 4229ef6c49d8SBart Van Assche * Remove all target ports. 4230aef9ec39SRoland Dreier */ 4231b3589fd4SMatthew Wilcox spin_lock(&host->target_lock); 4232ef6c49d8SBart Van Assche list_for_each_entry(target, &host->target_list, list) 4233ef6c49d8SBart Van Assche srp_queue_remove_work(target); 4234b3589fd4SMatthew Wilcox spin_unlock(&host->target_lock); 4235aef9ec39SRoland Dreier 4236aef9ec39SRoland Dreier /* 4237bcc05910SBart Van Assche * Wait for tl_err and target port removal tasks. 4238aef9ec39SRoland Dreier */ 4239ef6c49d8SBart Van Assche flush_workqueue(system_long_wq); 4240bcc05910SBart Van Assche flush_workqueue(srp_remove_wq); 4241aef9ec39SRoland Dreier 4242aef9ec39SRoland Dreier kfree(host); 4243aef9ec39SRoland Dreier } 4244aef9ec39SRoland Dreier 4245f5358a17SRoland Dreier ib_dealloc_pd(srp_dev->pd); 4246f5358a17SRoland Dreier 4247f5358a17SRoland Dreier kfree(srp_dev); 4248aef9ec39SRoland Dreier } 4249aef9ec39SRoland Dreier 42503236822bSFUJITA Tomonori static struct srp_function_template ib_srp_transport_functions = { 4251ed9b2264SBart Van Assche .has_rport_state = true, 4252ed9b2264SBart Van Assche .reset_timer_if_blocked = true, 4253a95cadb9SBart Van Assche .reconnect_delay = &srp_reconnect_delay, 4254ed9b2264SBart Van Assche .fast_io_fail_tmo = &srp_fast_io_fail_tmo, 4255ed9b2264SBart Van Assche .dev_loss_tmo = &srp_dev_loss_tmo, 4256ed9b2264SBart Van Assche .reconnect = srp_rport_reconnect, 4257dc1bdbd9SBart Van Assche .rport_delete = srp_rport_delete, 4258ed9b2264SBart Van Assche .terminate_rport_io = srp_terminate_io, 42593236822bSFUJITA Tomonori }; 42603236822bSFUJITA Tomonori 4261aef9ec39SRoland Dreier static int __init srp_init_module(void) 4262aef9ec39SRoland Dreier { 4263aef9ec39SRoland Dreier int ret; 4264aef9ec39SRoland Dreier 426516d14e01SBart Van Assche BUILD_BUG_ON(sizeof(struct srp_imm_buf) != 4); 426616d14e01SBart Van Assche BUILD_BUG_ON(sizeof(struct srp_login_req) != 64); 426716d14e01SBart Van Assche BUILD_BUG_ON(sizeof(struct srp_login_req_rdma) != 56); 426816d14e01SBart Van Assche BUILD_BUG_ON(sizeof(struct srp_cmd) != 48); 426916d14e01SBart Van Assche 427049248644SDavid Dillow if (srp_sg_tablesize) { 4271e0bda7d8SBart Van Assche pr_warn("srp_sg_tablesize is deprecated, please use cmd_sg_entries\n"); 427249248644SDavid Dillow if (!cmd_sg_entries) 427349248644SDavid Dillow cmd_sg_entries = srp_sg_tablesize; 427449248644SDavid Dillow } 427549248644SDavid Dillow 427649248644SDavid Dillow if (!cmd_sg_entries) 427749248644SDavid Dillow cmd_sg_entries = SRP_DEF_SG_TABLESIZE; 427849248644SDavid Dillow 427949248644SDavid Dillow if (cmd_sg_entries > 255) { 4280e0bda7d8SBart Van Assche pr_warn("Clamping cmd_sg_entries to 255\n"); 428149248644SDavid Dillow cmd_sg_entries = 255; 42821e89a194SDavid Dillow } 42831e89a194SDavid Dillow 4284c07d424dSDavid Dillow if (!indirect_sg_entries) 4285c07d424dSDavid Dillow indirect_sg_entries = cmd_sg_entries; 4286c07d424dSDavid Dillow else if (indirect_sg_entries < cmd_sg_entries) { 4287e0bda7d8SBart Van Assche pr_warn("Bumping up indirect_sg_entries to match cmd_sg_entries (%u)\n", 4288e0bda7d8SBart Van Assche cmd_sg_entries); 4289c07d424dSDavid Dillow indirect_sg_entries = cmd_sg_entries; 4290c07d424dSDavid Dillow } 4291c07d424dSDavid Dillow 42920a475ef4SIsrael Rukshin if (indirect_sg_entries > SG_MAX_SEGMENTS) { 42930a475ef4SIsrael Rukshin pr_warn("Clamping indirect_sg_entries to %u\n", 42940a475ef4SIsrael Rukshin SG_MAX_SEGMENTS); 42950a475ef4SIsrael Rukshin indirect_sg_entries = SG_MAX_SEGMENTS; 42960a475ef4SIsrael Rukshin } 42970a475ef4SIsrael Rukshin 4298bcc05910SBart Van Assche srp_remove_wq = create_workqueue("srp_remove"); 4299da05be29SWei Yongjun if (!srp_remove_wq) { 4300da05be29SWei Yongjun ret = -ENOMEM; 4301bcc05910SBart Van Assche goto out; 4302bcc05910SBart Van Assche } 4303bcc05910SBart Van Assche 4304bcc05910SBart Van Assche ret = -ENOMEM; 43053236822bSFUJITA Tomonori ib_srp_transport_template = 43063236822bSFUJITA Tomonori srp_attach_transport(&ib_srp_transport_functions); 43073236822bSFUJITA Tomonori if (!ib_srp_transport_template) 4308bcc05910SBart Van Assche goto destroy_wq; 43093236822bSFUJITA Tomonori 4310aef9ec39SRoland Dreier ret = class_register(&srp_class); 4311aef9ec39SRoland Dreier if (ret) { 4312e0bda7d8SBart Van Assche pr_err("couldn't register class infiniband_srp\n"); 4313bcc05910SBart Van Assche goto release_tr; 4314aef9ec39SRoland Dreier } 4315aef9ec39SRoland Dreier 4316c1a0b23bSMichael S. Tsirkin ib_sa_register_client(&srp_sa_client); 4317c1a0b23bSMichael S. Tsirkin 4318aef9ec39SRoland Dreier ret = ib_register_client(&srp_client); 4319aef9ec39SRoland Dreier if (ret) { 4320e0bda7d8SBart Van Assche pr_err("couldn't register IB client\n"); 4321bcc05910SBart Van Assche goto unreg_sa; 4322aef9ec39SRoland Dreier } 4323aef9ec39SRoland Dreier 4324bcc05910SBart Van Assche out: 4325bcc05910SBart Van Assche return ret; 4326bcc05910SBart Van Assche 4327bcc05910SBart Van Assche unreg_sa: 4328bcc05910SBart Van Assche ib_sa_unregister_client(&srp_sa_client); 4329bcc05910SBart Van Assche class_unregister(&srp_class); 4330bcc05910SBart Van Assche 4331bcc05910SBart Van Assche release_tr: 4332bcc05910SBart Van Assche srp_release_transport(ib_srp_transport_template); 4333bcc05910SBart Van Assche 4334bcc05910SBart Van Assche destroy_wq: 4335bcc05910SBart Van Assche destroy_workqueue(srp_remove_wq); 4336bcc05910SBart Van Assche goto out; 4337aef9ec39SRoland Dreier } 4338aef9ec39SRoland Dreier 4339aef9ec39SRoland Dreier static void __exit srp_cleanup_module(void) 4340aef9ec39SRoland Dreier { 4341aef9ec39SRoland Dreier ib_unregister_client(&srp_client); 4342c1a0b23bSMichael S. Tsirkin ib_sa_unregister_client(&srp_sa_client); 4343aef9ec39SRoland Dreier class_unregister(&srp_class); 43443236822bSFUJITA Tomonori srp_release_transport(ib_srp_transport_template); 4345bcc05910SBart Van Assche destroy_workqueue(srp_remove_wq); 4346aef9ec39SRoland Dreier } 4347aef9ec39SRoland Dreier 4348aef9ec39SRoland Dreier module_init(srp_init_module); 4349aef9ec39SRoland Dreier module_exit(srp_cleanup_module); 4350