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); 151dc1435c0SLeon Romanovsky static void srp_rename_dev(struct ib_device *device, void *client_data); 1521dc7b1f1SChristoph Hellwig static void srp_recv_done(struct ib_cq *cq, struct ib_wc *wc); 1531dc7b1f1SChristoph Hellwig static void srp_handle_qp_err(struct ib_cq *cq, struct ib_wc *wc, 1541dc7b1f1SChristoph Hellwig const char *opname); 155e7ff98aeSParav Pandit static int srp_ib_cm_handler(struct ib_cm_id *cm_id, 156e7ff98aeSParav Pandit const struct ib_cm_event *event); 15719f31343SBart Van Assche static int srp_rdma_cm_handler(struct rdma_cm_id *cm_id, 15819f31343SBart Van Assche struct rdma_cm_event *event); 159aef9ec39SRoland Dreier 1603236822bSFUJITA Tomonori static struct scsi_transport_template *ib_srp_transport_template; 161bcc05910SBart Van Assche static struct workqueue_struct *srp_remove_wq; 1623236822bSFUJITA Tomonori 163aef9ec39SRoland Dreier static struct ib_client srp_client = { 164aef9ec39SRoland Dreier .name = "srp", 165aef9ec39SRoland Dreier .add = srp_add_one, 166dc1435c0SLeon Romanovsky .remove = srp_remove_one, 167dc1435c0SLeon Romanovsky .rename = srp_rename_dev 168aef9ec39SRoland Dreier }; 169aef9ec39SRoland Dreier 170c1a0b23bSMichael S. Tsirkin static struct ib_sa_client srp_sa_client; 171c1a0b23bSMichael S. Tsirkin 172ed9b2264SBart Van Assche static int srp_tmo_get(char *buffer, const struct kernel_param *kp) 173ed9b2264SBart Van Assche { 174ed9b2264SBart Van Assche int tmo = *(int *)kp->arg; 175ed9b2264SBart Van Assche 176ed9b2264SBart Van Assche if (tmo >= 0) 177ed9b2264SBart Van Assche return sprintf(buffer, "%d", tmo); 178ed9b2264SBart Van Assche else 179ed9b2264SBart Van Assche return sprintf(buffer, "off"); 180ed9b2264SBart Van Assche } 181ed9b2264SBart Van Assche 182ed9b2264SBart Van Assche static int srp_tmo_set(const char *val, const struct kernel_param *kp) 183ed9b2264SBart Van Assche { 184ed9b2264SBart Van Assche int tmo, res; 185ed9b2264SBart Van Assche 1863fdf70acSSagi Grimberg res = srp_parse_tmo(&tmo, val); 187ed9b2264SBart Van Assche if (res) 188ed9b2264SBart Van Assche goto out; 1893fdf70acSSagi Grimberg 190a95cadb9SBart Van Assche if (kp->arg == &srp_reconnect_delay) 191a95cadb9SBart Van Assche res = srp_tmo_valid(tmo, srp_fast_io_fail_tmo, 192a95cadb9SBart Van Assche srp_dev_loss_tmo); 193a95cadb9SBart Van Assche else if (kp->arg == &srp_fast_io_fail_tmo) 194a95cadb9SBart Van Assche res = srp_tmo_valid(srp_reconnect_delay, tmo, srp_dev_loss_tmo); 195ed9b2264SBart Van Assche else 196a95cadb9SBart Van Assche res = srp_tmo_valid(srp_reconnect_delay, srp_fast_io_fail_tmo, 197a95cadb9SBart Van Assche tmo); 198ed9b2264SBart Van Assche if (res) 199ed9b2264SBart Van Assche goto out; 200ed9b2264SBart Van Assche *(int *)kp->arg = tmo; 201ed9b2264SBart Van Assche 202ed9b2264SBart Van Assche out: 203ed9b2264SBart Van Assche return res; 204ed9b2264SBart Van Assche } 205ed9b2264SBart Van Assche 2069c27847dSLuis R. Rodriguez static const struct kernel_param_ops srp_tmo_ops = { 207ed9b2264SBart Van Assche .get = srp_tmo_get, 208ed9b2264SBart Van Assche .set = srp_tmo_set, 209ed9b2264SBart Van Assche }; 210ed9b2264SBart Van Assche 211aef9ec39SRoland Dreier static inline struct srp_target_port *host_to_target(struct Scsi_Host *host) 212aef9ec39SRoland Dreier { 213aef9ec39SRoland Dreier return (struct srp_target_port *) host->hostdata; 214aef9ec39SRoland Dreier } 215aef9ec39SRoland Dreier 216aef9ec39SRoland Dreier static const char *srp_target_info(struct Scsi_Host *host) 217aef9ec39SRoland Dreier { 218aef9ec39SRoland Dreier return host_to_target(host)->target_name; 219aef9ec39SRoland Dreier } 220aef9ec39SRoland Dreier 2215d7cbfd6SRoland Dreier static int srp_target_is_topspin(struct srp_target_port *target) 2225d7cbfd6SRoland Dreier { 2235d7cbfd6SRoland Dreier static const u8 topspin_oui[3] = { 0x00, 0x05, 0xad }; 2243d1ff48dSRaghava Kondapalli static const u8 cisco_oui[3] = { 0x00, 0x1b, 0x0d }; 2255d7cbfd6SRoland Dreier 2265d7cbfd6SRoland Dreier return topspin_workarounds && 2273d1ff48dSRaghava Kondapalli (!memcmp(&target->ioc_guid, topspin_oui, sizeof topspin_oui) || 2283d1ff48dSRaghava Kondapalli !memcmp(&target->ioc_guid, cisco_oui, sizeof cisco_oui)); 2295d7cbfd6SRoland Dreier } 2305d7cbfd6SRoland Dreier 231aef9ec39SRoland Dreier static struct srp_iu *srp_alloc_iu(struct srp_host *host, size_t size, 232aef9ec39SRoland Dreier gfp_t gfp_mask, 233aef9ec39SRoland Dreier enum dma_data_direction direction) 234aef9ec39SRoland Dreier { 235aef9ec39SRoland Dreier struct srp_iu *iu; 236aef9ec39SRoland Dreier 237aef9ec39SRoland Dreier iu = kmalloc(sizeof *iu, gfp_mask); 238aef9ec39SRoland Dreier if (!iu) 239aef9ec39SRoland Dreier goto out; 240aef9ec39SRoland Dreier 241aef9ec39SRoland Dreier iu->buf = kzalloc(size, gfp_mask); 242aef9ec39SRoland Dreier if (!iu->buf) 243aef9ec39SRoland Dreier goto out_free_iu; 244aef9ec39SRoland Dreier 24505321937SGreg Kroah-Hartman iu->dma = ib_dma_map_single(host->srp_dev->dev, iu->buf, size, 24605321937SGreg Kroah-Hartman direction); 24705321937SGreg Kroah-Hartman if (ib_dma_mapping_error(host->srp_dev->dev, iu->dma)) 248aef9ec39SRoland Dreier goto out_free_buf; 249aef9ec39SRoland Dreier 250aef9ec39SRoland Dreier iu->size = size; 251aef9ec39SRoland Dreier iu->direction = direction; 252aef9ec39SRoland Dreier 253aef9ec39SRoland Dreier return iu; 254aef9ec39SRoland Dreier 255aef9ec39SRoland Dreier out_free_buf: 256aef9ec39SRoland Dreier kfree(iu->buf); 257aef9ec39SRoland Dreier out_free_iu: 258aef9ec39SRoland Dreier kfree(iu); 259aef9ec39SRoland Dreier out: 260aef9ec39SRoland Dreier return NULL; 261aef9ec39SRoland Dreier } 262aef9ec39SRoland Dreier 263aef9ec39SRoland Dreier static void srp_free_iu(struct srp_host *host, struct srp_iu *iu) 264aef9ec39SRoland Dreier { 265aef9ec39SRoland Dreier if (!iu) 266aef9ec39SRoland Dreier return; 267aef9ec39SRoland Dreier 26805321937SGreg Kroah-Hartman ib_dma_unmap_single(host->srp_dev->dev, iu->dma, iu->size, 26905321937SGreg Kroah-Hartman iu->direction); 270aef9ec39SRoland Dreier kfree(iu->buf); 271aef9ec39SRoland Dreier kfree(iu); 272aef9ec39SRoland Dreier } 273aef9ec39SRoland Dreier 274aef9ec39SRoland Dreier static void srp_qp_event(struct ib_event *event, void *context) 275aef9ec39SRoland Dreier { 27657363d98SSagi Grimberg pr_debug("QP event %s (%d)\n", 27757363d98SSagi Grimberg ib_event_msg(event->event), event->event); 278aef9ec39SRoland Dreier } 279aef9ec39SRoland Dreier 28019f31343SBart Van Assche static int srp_init_ib_qp(struct srp_target_port *target, 281aef9ec39SRoland Dreier struct ib_qp *qp) 282aef9ec39SRoland Dreier { 283aef9ec39SRoland Dreier struct ib_qp_attr *attr; 284aef9ec39SRoland Dreier int ret; 285aef9ec39SRoland Dreier 286aef9ec39SRoland Dreier attr = kmalloc(sizeof *attr, GFP_KERNEL); 287aef9ec39SRoland Dreier if (!attr) 288aef9ec39SRoland Dreier return -ENOMEM; 289aef9ec39SRoland Dreier 29056b5390cSBart Van Assche ret = ib_find_cached_pkey(target->srp_host->srp_dev->dev, 291aef9ec39SRoland Dreier target->srp_host->port, 29219f31343SBart Van Assche be16_to_cpu(target->ib_cm.pkey), 293aef9ec39SRoland Dreier &attr->pkey_index); 294aef9ec39SRoland Dreier if (ret) 295aef9ec39SRoland Dreier goto out; 296aef9ec39SRoland Dreier 297aef9ec39SRoland Dreier attr->qp_state = IB_QPS_INIT; 298aef9ec39SRoland Dreier attr->qp_access_flags = (IB_ACCESS_REMOTE_READ | 299aef9ec39SRoland Dreier IB_ACCESS_REMOTE_WRITE); 300aef9ec39SRoland Dreier attr->port_num = target->srp_host->port; 301aef9ec39SRoland Dreier 302aef9ec39SRoland Dreier ret = ib_modify_qp(qp, attr, 303aef9ec39SRoland Dreier IB_QP_STATE | 304aef9ec39SRoland Dreier IB_QP_PKEY_INDEX | 305aef9ec39SRoland Dreier IB_QP_ACCESS_FLAGS | 306aef9ec39SRoland Dreier IB_QP_PORT); 307aef9ec39SRoland Dreier 308aef9ec39SRoland Dreier out: 309aef9ec39SRoland Dreier kfree(attr); 310aef9ec39SRoland Dreier return ret; 311aef9ec39SRoland Dreier } 312aef9ec39SRoland Dreier 31319f31343SBart Van Assche static int srp_new_ib_cm_id(struct srp_rdma_ch *ch) 3149fe4bcf4SDavid Dillow { 315509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 3169fe4bcf4SDavid Dillow struct ib_cm_id *new_cm_id; 3179fe4bcf4SDavid Dillow 31805321937SGreg Kroah-Hartman new_cm_id = ib_create_cm_id(target->srp_host->srp_dev->dev, 31919f31343SBart Van Assche srp_ib_cm_handler, ch); 3209fe4bcf4SDavid Dillow if (IS_ERR(new_cm_id)) 3219fe4bcf4SDavid Dillow return PTR_ERR(new_cm_id); 3229fe4bcf4SDavid Dillow 32319f31343SBart Van Assche if (ch->ib_cm.cm_id) 32419f31343SBart Van Assche ib_destroy_cm_id(ch->ib_cm.cm_id); 32519f31343SBart Van Assche ch->ib_cm.cm_id = new_cm_id; 3264c33bd19SDasaratharaman Chandramouli if (rdma_cap_opa_ah(target->srp_host->srp_dev->dev, 3274c33bd19SDasaratharaman Chandramouli target->srp_host->port)) 32819f31343SBart Van Assche ch->ib_cm.path.rec_type = SA_PATH_REC_TYPE_OPA; 3294c33bd19SDasaratharaman Chandramouli else 33019f31343SBart Van Assche ch->ib_cm.path.rec_type = SA_PATH_REC_TYPE_IB; 33119f31343SBart Van Assche ch->ib_cm.path.sgid = target->sgid; 33219f31343SBart Van Assche ch->ib_cm.path.dgid = target->ib_cm.orig_dgid; 33319f31343SBart Van Assche ch->ib_cm.path.pkey = target->ib_cm.pkey; 33419f31343SBart Van Assche ch->ib_cm.path.service_id = target->ib_cm.service_id; 3359fe4bcf4SDavid Dillow 3369fe4bcf4SDavid Dillow return 0; 3379fe4bcf4SDavid Dillow } 3389fe4bcf4SDavid Dillow 33919f31343SBart Van Assche static int srp_new_rdma_cm_id(struct srp_rdma_ch *ch) 34019f31343SBart Van Assche { 34119f31343SBart Van Assche struct srp_target_port *target = ch->target; 34219f31343SBart Van Assche struct rdma_cm_id *new_cm_id; 34319f31343SBart Van Assche int ret; 34419f31343SBart Van Assche 34519f31343SBart Van Assche new_cm_id = rdma_create_id(target->net, srp_rdma_cm_handler, ch, 34619f31343SBart Van Assche RDMA_PS_TCP, IB_QPT_RC); 34719f31343SBart Van Assche if (IS_ERR(new_cm_id)) { 34819f31343SBart Van Assche ret = PTR_ERR(new_cm_id); 34919f31343SBart Van Assche new_cm_id = NULL; 35019f31343SBart Van Assche goto out; 35119f31343SBart Van Assche } 35219f31343SBart Van Assche 35319f31343SBart Van Assche init_completion(&ch->done); 35419f31343SBart Van Assche ret = rdma_resolve_addr(new_cm_id, target->rdma_cm.src_specified ? 35514673778SBart Van Assche &target->rdma_cm.src.sa : NULL, 35614673778SBart Van Assche &target->rdma_cm.dst.sa, 35719f31343SBart Van Assche SRP_PATH_REC_TIMEOUT_MS); 35819f31343SBart Van Assche if (ret) { 359fdbcf5c0SBart Van Assche pr_err("No route available from %pISpsc to %pISpsc (%d)\n", 3607da09af9SBart Van Assche &target->rdma_cm.src, &target->rdma_cm.dst, ret); 36119f31343SBart Van Assche goto out; 36219f31343SBart Van Assche } 36319f31343SBart Van Assche ret = wait_for_completion_interruptible(&ch->done); 36419f31343SBart Van Assche if (ret < 0) 36519f31343SBart Van Assche goto out; 36619f31343SBart Van Assche 36719f31343SBart Van Assche ret = ch->status; 36819f31343SBart Van Assche if (ret) { 369fdbcf5c0SBart Van Assche pr_err("Resolving address %pISpsc failed (%d)\n", 3707da09af9SBart Van Assche &target->rdma_cm.dst, ret); 37119f31343SBart Van Assche goto out; 37219f31343SBart Van Assche } 37319f31343SBart Van Assche 37419f31343SBart Van Assche swap(ch->rdma_cm.cm_id, new_cm_id); 37519f31343SBart Van Assche 37619f31343SBart Van Assche out: 37719f31343SBart Van Assche if (new_cm_id) 37819f31343SBart Van Assche rdma_destroy_id(new_cm_id); 37919f31343SBart Van Assche 38019f31343SBart Van Assche return ret; 38119f31343SBart Van Assche } 38219f31343SBart Van Assche 38319f31343SBart Van Assche static int srp_new_cm_id(struct srp_rdma_ch *ch) 38419f31343SBart Van Assche { 38519f31343SBart Van Assche struct srp_target_port *target = ch->target; 38619f31343SBart Van Assche 38719f31343SBart Van Assche return target->using_rdma_cm ? srp_new_rdma_cm_id(ch) : 38819f31343SBart Van Assche srp_new_ib_cm_id(ch); 38919f31343SBart Van Assche } 39019f31343SBart Van Assche 391d1b4289eSBart Van Assche static struct ib_fmr_pool *srp_alloc_fmr_pool(struct srp_target_port *target) 392d1b4289eSBart Van Assche { 393d1b4289eSBart Van Assche struct srp_device *dev = target->srp_host->srp_dev; 394d1b4289eSBart Van Assche struct ib_fmr_pool_param fmr_param; 395d1b4289eSBart Van Assche 396d1b4289eSBart Van Assche memset(&fmr_param, 0, sizeof(fmr_param)); 397fa9863f8SBart Van Assche fmr_param.pool_size = target->mr_pool_size; 398d1b4289eSBart Van Assche fmr_param.dirty_watermark = fmr_param.pool_size / 4; 399d1b4289eSBart Van Assche fmr_param.cache = 1; 40052ede08fSBart Van Assche fmr_param.max_pages_per_fmr = dev->max_pages_per_mr; 40152ede08fSBart Van Assche fmr_param.page_shift = ilog2(dev->mr_page_size); 402d1b4289eSBart Van Assche fmr_param.access = (IB_ACCESS_LOCAL_WRITE | 403d1b4289eSBart Van Assche IB_ACCESS_REMOTE_WRITE | 404d1b4289eSBart Van Assche IB_ACCESS_REMOTE_READ); 405d1b4289eSBart Van Assche 406d1b4289eSBart Van Assche return ib_create_fmr_pool(dev->pd, &fmr_param); 407d1b4289eSBart Van Assche } 408d1b4289eSBart Van Assche 4095cfb1782SBart Van Assche /** 4105cfb1782SBart Van Assche * srp_destroy_fr_pool() - free the resources owned by a pool 4115cfb1782SBart Van Assche * @pool: Fast registration pool to be destroyed. 4125cfb1782SBart Van Assche */ 4135cfb1782SBart Van Assche static void srp_destroy_fr_pool(struct srp_fr_pool *pool) 4145cfb1782SBart Van Assche { 4155cfb1782SBart Van Assche int i; 4165cfb1782SBart Van Assche struct srp_fr_desc *d; 4175cfb1782SBart Van Assche 4185cfb1782SBart Van Assche if (!pool) 4195cfb1782SBart Van Assche return; 4205cfb1782SBart Van Assche 4215cfb1782SBart Van Assche for (i = 0, d = &pool->desc[0]; i < pool->size; i++, d++) { 4225cfb1782SBart Van Assche if (d->mr) 4235cfb1782SBart Van Assche ib_dereg_mr(d->mr); 4245cfb1782SBart Van Assche } 4255cfb1782SBart Van Assche kfree(pool); 4265cfb1782SBart Van Assche } 4275cfb1782SBart Van Assche 4285cfb1782SBart Van Assche /** 4295cfb1782SBart Van Assche * srp_create_fr_pool() - allocate and initialize a pool for fast registration 4305cfb1782SBart Van Assche * @device: IB device to allocate fast registration descriptors for. 4315cfb1782SBart Van Assche * @pd: Protection domain associated with the FR descriptors. 4325cfb1782SBart Van Assche * @pool_size: Number of descriptors to allocate. 4335cfb1782SBart Van Assche * @max_page_list_len: Maximum fast registration work request page list length. 4345cfb1782SBart Van Assche */ 4355cfb1782SBart Van Assche static struct srp_fr_pool *srp_create_fr_pool(struct ib_device *device, 4365cfb1782SBart Van Assche struct ib_pd *pd, int pool_size, 4375cfb1782SBart Van Assche int max_page_list_len) 4385cfb1782SBart Van Assche { 4395cfb1782SBart Van Assche struct srp_fr_pool *pool; 4405cfb1782SBart Van Assche struct srp_fr_desc *d; 4415cfb1782SBart Van Assche struct ib_mr *mr; 4425cfb1782SBart Van Assche int i, ret = -EINVAL; 443fbd36818SSergey Gorenko enum ib_mr_type mr_type; 4445cfb1782SBart Van Assche 4455cfb1782SBart Van Assche if (pool_size <= 0) 4465cfb1782SBart Van Assche goto err; 4475cfb1782SBart Van Assche ret = -ENOMEM; 4487a7b0feaSGustavo A. R. Silva pool = kzalloc(struct_size(pool, desc, pool_size), GFP_KERNEL); 4495cfb1782SBart Van Assche if (!pool) 4505cfb1782SBart Van Assche goto err; 4515cfb1782SBart Van Assche pool->size = pool_size; 4525cfb1782SBart Van Assche pool->max_page_list_len = max_page_list_len; 4535cfb1782SBart Van Assche spin_lock_init(&pool->lock); 4545cfb1782SBart Van Assche INIT_LIST_HEAD(&pool->free_list); 4555cfb1782SBart Van Assche 456fbd36818SSergey Gorenko if (device->attrs.device_cap_flags & IB_DEVICE_SG_GAPS_REG) 457fbd36818SSergey Gorenko mr_type = IB_MR_TYPE_SG_GAPS; 458fbd36818SSergey Gorenko else 459fbd36818SSergey Gorenko mr_type = IB_MR_TYPE_MEM_REG; 460fbd36818SSergey Gorenko 4615cfb1782SBart Van Assche for (i = 0, d = &pool->desc[0]; i < pool->size; i++, d++) { 462fbd36818SSergey Gorenko mr = ib_alloc_mr(pd, mr_type, max_page_list_len); 4635cfb1782SBart Van Assche if (IS_ERR(mr)) { 4645cfb1782SBart Van Assche ret = PTR_ERR(mr); 4653787d990SBart Van Assche if (ret == -ENOMEM) 4663787d990SBart Van Assche pr_info("%s: ib_alloc_mr() failed. Try to reduce max_cmd_per_lun, max_sect or ch_count\n", 4673787d990SBart Van Assche dev_name(&device->dev)); 4685cfb1782SBart Van Assche goto destroy_pool; 4695cfb1782SBart Van Assche } 4705cfb1782SBart Van Assche d->mr = mr; 4715cfb1782SBart Van Assche list_add_tail(&d->entry, &pool->free_list); 4725cfb1782SBart Van Assche } 4735cfb1782SBart Van Assche 4745cfb1782SBart Van Assche out: 4755cfb1782SBart Van Assche return pool; 4765cfb1782SBart Van Assche 4775cfb1782SBart Van Assche destroy_pool: 4785cfb1782SBart Van Assche srp_destroy_fr_pool(pool); 4795cfb1782SBart Van Assche 4805cfb1782SBart Van Assche err: 4815cfb1782SBart Van Assche pool = ERR_PTR(ret); 4825cfb1782SBart Van Assche goto out; 4835cfb1782SBart Van Assche } 4845cfb1782SBart Van Assche 4855cfb1782SBart Van Assche /** 4865cfb1782SBart Van Assche * srp_fr_pool_get() - obtain a descriptor suitable for fast registration 4875cfb1782SBart Van Assche * @pool: Pool to obtain descriptor from. 4885cfb1782SBart Van Assche */ 4895cfb1782SBart Van Assche static struct srp_fr_desc *srp_fr_pool_get(struct srp_fr_pool *pool) 4905cfb1782SBart Van Assche { 4915cfb1782SBart Van Assche struct srp_fr_desc *d = NULL; 4925cfb1782SBart Van Assche unsigned long flags; 4935cfb1782SBart Van Assche 4945cfb1782SBart Van Assche spin_lock_irqsave(&pool->lock, flags); 4955cfb1782SBart Van Assche if (!list_empty(&pool->free_list)) { 4965cfb1782SBart Van Assche d = list_first_entry(&pool->free_list, typeof(*d), entry); 4975cfb1782SBart Van Assche list_del(&d->entry); 4985cfb1782SBart Van Assche } 4995cfb1782SBart Van Assche spin_unlock_irqrestore(&pool->lock, flags); 5005cfb1782SBart Van Assche 5015cfb1782SBart Van Assche return d; 5025cfb1782SBart Van Assche } 5035cfb1782SBart Van Assche 5045cfb1782SBart Van Assche /** 5055cfb1782SBart Van Assche * srp_fr_pool_put() - put an FR descriptor back in the free list 5065cfb1782SBart Van Assche * @pool: Pool the descriptor was allocated from. 5075cfb1782SBart Van Assche * @desc: Pointer to an array of fast registration descriptor pointers. 5085cfb1782SBart Van Assche * @n: Number of descriptors to put back. 5095cfb1782SBart Van Assche * 5105cfb1782SBart Van Assche * Note: The caller must already have queued an invalidation request for 5115cfb1782SBart Van Assche * desc->mr->rkey before calling this function. 5125cfb1782SBart Van Assche */ 5135cfb1782SBart Van Assche static void srp_fr_pool_put(struct srp_fr_pool *pool, struct srp_fr_desc **desc, 5145cfb1782SBart Van Assche int n) 5155cfb1782SBart Van Assche { 5165cfb1782SBart Van Assche unsigned long flags; 5175cfb1782SBart Van Assche int i; 5185cfb1782SBart Van Assche 5195cfb1782SBart Van Assche spin_lock_irqsave(&pool->lock, flags); 5205cfb1782SBart Van Assche for (i = 0; i < n; i++) 5215cfb1782SBart Van Assche list_add(&desc[i]->entry, &pool->free_list); 5225cfb1782SBart Van Assche spin_unlock_irqrestore(&pool->lock, flags); 5235cfb1782SBart Van Assche } 5245cfb1782SBart Van Assche 5255cfb1782SBart Van Assche static struct srp_fr_pool *srp_alloc_fr_pool(struct srp_target_port *target) 5265cfb1782SBart Van Assche { 5275cfb1782SBart Van Assche struct srp_device *dev = target->srp_host->srp_dev; 5285cfb1782SBart Van Assche 529fa9863f8SBart Van Assche return srp_create_fr_pool(dev->dev, dev->pd, target->mr_pool_size, 5305cfb1782SBart Van Assche dev->max_pages_per_mr); 5315cfb1782SBart Van Assche } 5325cfb1782SBart Van Assche 5337dad6b2eSBart Van Assche /** 5347dad6b2eSBart Van Assche * srp_destroy_qp() - destroy an RDMA queue pair 5359566b054SBart Van Assche * @ch: SRP RDMA channel. 5367dad6b2eSBart Van Assche * 537561392d4SSteve Wise * Drain the qp before destroying it. This avoids that the receive 538561392d4SSteve Wise * completion handler can access the queue pair while it is 5397dad6b2eSBart Van Assche * being destroyed. 5407dad6b2eSBart Van Assche */ 5419566b054SBart Van Assche static void srp_destroy_qp(struct srp_rdma_ch *ch) 5427dad6b2eSBart Van Assche { 5439294000dSBart Van Assche spin_lock_irq(&ch->lock); 5449294000dSBart Van Assche ib_process_cq_direct(ch->send_cq, -1); 5459294000dSBart Van Assche spin_unlock_irq(&ch->lock); 5469294000dSBart Van Assche 5479566b054SBart Van Assche ib_drain_qp(ch->qp); 5489566b054SBart Van Assche ib_destroy_qp(ch->qp); 5497dad6b2eSBart Van Assche } 5507dad6b2eSBart Van Assche 551509c07bcSBart Van Assche static int srp_create_ch_ib(struct srp_rdma_ch *ch) 552aef9ec39SRoland Dreier { 553509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 55462154b2eSBart Van Assche struct srp_device *dev = target->srp_host->srp_dev; 555bf583470SBart Van Assche const struct ib_device_attr *attr = &dev->dev->attrs; 556aef9ec39SRoland Dreier struct ib_qp_init_attr *init_attr; 55773aa89edSIshai Rabinovitz struct ib_cq *recv_cq, *send_cq; 55873aa89edSIshai Rabinovitz struct ib_qp *qp; 559d1b4289eSBart Van Assche struct ib_fmr_pool *fmr_pool = NULL; 5605cfb1782SBart Van Assche struct srp_fr_pool *fr_pool = NULL; 561509c5f33SBart Van Assche const int m = 1 + dev->use_fast_reg * target->mr_per_cmd * 2; 562aef9ec39SRoland Dreier int ret; 563aef9ec39SRoland Dreier 564aef9ec39SRoland Dreier init_attr = kzalloc(sizeof *init_attr, GFP_KERNEL); 565aef9ec39SRoland Dreier if (!init_attr) 566aef9ec39SRoland Dreier return -ENOMEM; 567aef9ec39SRoland Dreier 568561392d4SSteve Wise /* queue_size + 1 for ib_drain_rq() */ 5691dc7b1f1SChristoph Hellwig recv_cq = ib_alloc_cq(dev->dev, ch, target->queue_size + 1, 5701dc7b1f1SChristoph Hellwig ch->comp_vector, IB_POLL_SOFTIRQ); 57173aa89edSIshai Rabinovitz if (IS_ERR(recv_cq)) { 57273aa89edSIshai Rabinovitz ret = PTR_ERR(recv_cq); 573da9d2f07SRoland Dreier goto err; 574aef9ec39SRoland Dreier } 575aef9ec39SRoland Dreier 5761dc7b1f1SChristoph Hellwig send_cq = ib_alloc_cq(dev->dev, ch, m * target->queue_size, 5771dc7b1f1SChristoph Hellwig ch->comp_vector, IB_POLL_DIRECT); 57873aa89edSIshai Rabinovitz if (IS_ERR(send_cq)) { 57973aa89edSIshai Rabinovitz ret = PTR_ERR(send_cq); 580da9d2f07SRoland Dreier goto err_recv_cq; 5819c03dc9fSBart Van Assche } 5829c03dc9fSBart Van Assche 583aef9ec39SRoland Dreier init_attr->event_handler = srp_qp_event; 5845cfb1782SBart Van Assche init_attr->cap.max_send_wr = m * target->queue_size; 5857dad6b2eSBart Van Assche init_attr->cap.max_recv_wr = target->queue_size + 1; 586aef9ec39SRoland Dreier init_attr->cap.max_recv_sge = 1; 587bf583470SBart Van Assche init_attr->cap.max_send_sge = min(SRP_MAX_SGE, attr->max_send_sge); 5885cfb1782SBart Van Assche init_attr->sq_sig_type = IB_SIGNAL_REQ_WR; 589aef9ec39SRoland Dreier init_attr->qp_type = IB_QPT_RC; 59073aa89edSIshai Rabinovitz init_attr->send_cq = send_cq; 59173aa89edSIshai Rabinovitz init_attr->recv_cq = recv_cq; 592aef9ec39SRoland Dreier 593bf583470SBart Van Assche ch->max_imm_sge = min(init_attr->cap.max_send_sge - 1U, 255U); 594bf583470SBart Van Assche 59519f31343SBart Van Assche if (target->using_rdma_cm) { 59619f31343SBart Van Assche ret = rdma_create_qp(ch->rdma_cm.cm_id, dev->pd, init_attr); 59719f31343SBart Van Assche qp = ch->rdma_cm.cm_id->qp; 59819f31343SBart Van Assche } else { 59962154b2eSBart Van Assche qp = ib_create_qp(dev->pd, init_attr); 60019f31343SBart Van Assche if (!IS_ERR(qp)) { 60119f31343SBart Van Assche ret = srp_init_ib_qp(target, qp); 60219f31343SBart Van Assche if (ret) 60319f31343SBart Van Assche ib_destroy_qp(qp); 60419f31343SBart Van Assche } else { 60573aa89edSIshai Rabinovitz ret = PTR_ERR(qp); 60619f31343SBart Van Assche } 60719f31343SBart Van Assche } 60819f31343SBart Van Assche if (ret) { 60919f31343SBart Van Assche pr_err("QP creation failed for dev %s: %d\n", 61019f31343SBart Van Assche dev_name(&dev->dev->dev), ret); 611da9d2f07SRoland Dreier goto err_send_cq; 612aef9ec39SRoland Dreier } 613aef9ec39SRoland Dreier 614002f1567SBart Van Assche if (dev->use_fast_reg) { 6155cfb1782SBart Van Assche fr_pool = srp_alloc_fr_pool(target); 6165cfb1782SBart Van Assche if (IS_ERR(fr_pool)) { 6175cfb1782SBart Van Assche ret = PTR_ERR(fr_pool); 6185cfb1782SBart Van Assche shost_printk(KERN_WARNING, target->scsi_host, PFX 6195cfb1782SBart Van Assche "FR pool allocation failed (%d)\n", ret); 6205cfb1782SBart Van Assche goto err_qp; 6215cfb1782SBart Van Assche } 622002f1567SBart Van Assche } else if (dev->use_fmr) { 623d1b4289eSBart Van Assche fmr_pool = srp_alloc_fmr_pool(target); 624d1b4289eSBart Van Assche if (IS_ERR(fmr_pool)) { 625d1b4289eSBart Van Assche ret = PTR_ERR(fmr_pool); 626d1b4289eSBart Van Assche shost_printk(KERN_WARNING, target->scsi_host, PFX 627d1b4289eSBart Van Assche "FMR pool allocation failed (%d)\n", ret); 628d1b4289eSBart Van Assche goto err_qp; 629d1b4289eSBart Van Assche } 630d1b4289eSBart Van Assche } 631d1b4289eSBart Van Assche 632509c07bcSBart Van Assche if (ch->qp) 6339566b054SBart Van Assche srp_destroy_qp(ch); 634509c07bcSBart Van Assche if (ch->recv_cq) 6351dc7b1f1SChristoph Hellwig ib_free_cq(ch->recv_cq); 636509c07bcSBart Van Assche if (ch->send_cq) 6371dc7b1f1SChristoph Hellwig ib_free_cq(ch->send_cq); 63873aa89edSIshai Rabinovitz 639509c07bcSBart Van Assche ch->qp = qp; 640509c07bcSBart Van Assche ch->recv_cq = recv_cq; 641509c07bcSBart Van Assche ch->send_cq = send_cq; 64273aa89edSIshai Rabinovitz 6437fbc67dfSSagi Grimberg if (dev->use_fast_reg) { 6447fbc67dfSSagi Grimberg if (ch->fr_pool) 6457fbc67dfSSagi Grimberg srp_destroy_fr_pool(ch->fr_pool); 6467fbc67dfSSagi Grimberg ch->fr_pool = fr_pool; 6477fbc67dfSSagi Grimberg } else if (dev->use_fmr) { 6487fbc67dfSSagi Grimberg if (ch->fmr_pool) 6497fbc67dfSSagi Grimberg ib_destroy_fmr_pool(ch->fmr_pool); 6507fbc67dfSSagi Grimberg ch->fmr_pool = fmr_pool; 6517fbc67dfSSagi Grimberg } 6527fbc67dfSSagi Grimberg 653da9d2f07SRoland Dreier kfree(init_attr); 654da9d2f07SRoland Dreier return 0; 655da9d2f07SRoland Dreier 656da9d2f07SRoland Dreier err_qp: 65719f31343SBart Van Assche if (target->using_rdma_cm) 65819f31343SBart Van Assche rdma_destroy_qp(ch->rdma_cm.cm_id); 65919f31343SBart Van Assche else 66095c2ef50SIsrael Rukshin ib_destroy_qp(qp); 661da9d2f07SRoland Dreier 662da9d2f07SRoland Dreier err_send_cq: 6631dc7b1f1SChristoph Hellwig ib_free_cq(send_cq); 664da9d2f07SRoland Dreier 665da9d2f07SRoland Dreier err_recv_cq: 6661dc7b1f1SChristoph Hellwig ib_free_cq(recv_cq); 667da9d2f07SRoland Dreier 668da9d2f07SRoland Dreier err: 669aef9ec39SRoland Dreier kfree(init_attr); 670aef9ec39SRoland Dreier return ret; 671aef9ec39SRoland Dreier } 672aef9ec39SRoland Dreier 6734d73f95fSBart Van Assche /* 6744d73f95fSBart Van Assche * Note: this function may be called without srp_alloc_iu_bufs() having been 675509c07bcSBart Van Assche * invoked. Hence the ch->[rt]x_ring checks. 6764d73f95fSBart Van Assche */ 677509c07bcSBart Van Assche static void srp_free_ch_ib(struct srp_target_port *target, 678509c07bcSBart Van Assche struct srp_rdma_ch *ch) 679aef9ec39SRoland Dreier { 6805cfb1782SBart Van Assche struct srp_device *dev = target->srp_host->srp_dev; 681aef9ec39SRoland Dreier int i; 682aef9ec39SRoland Dreier 683d92c0da7SBart Van Assche if (!ch->target) 684d92c0da7SBart Van Assche return; 685d92c0da7SBart Van Assche 68619f31343SBart Van Assche if (target->using_rdma_cm) { 68719f31343SBart Van Assche if (ch->rdma_cm.cm_id) { 68819f31343SBart Van Assche rdma_destroy_id(ch->rdma_cm.cm_id); 68919f31343SBart Van Assche ch->rdma_cm.cm_id = NULL; 69019f31343SBart Van Assche } 69119f31343SBart Van Assche } else { 69219f31343SBart Van Assche if (ch->ib_cm.cm_id) { 69319f31343SBart Van Assche ib_destroy_cm_id(ch->ib_cm.cm_id); 69419f31343SBart Van Assche ch->ib_cm.cm_id = NULL; 69519f31343SBart Van Assche } 696394c595eSBart Van Assche } 697394c595eSBart Van Assche 698d92c0da7SBart Van Assche /* If srp_new_cm_id() succeeded but srp_create_ch_ib() not, return. */ 699d92c0da7SBart Van Assche if (!ch->qp) 700d92c0da7SBart Van Assche return; 701d92c0da7SBart Van Assche 7025cfb1782SBart Van Assche if (dev->use_fast_reg) { 703509c07bcSBart Van Assche if (ch->fr_pool) 704509c07bcSBart Van Assche srp_destroy_fr_pool(ch->fr_pool); 705002f1567SBart Van Assche } else if (dev->use_fmr) { 706509c07bcSBart Van Assche if (ch->fmr_pool) 707509c07bcSBart Van Assche ib_destroy_fmr_pool(ch->fmr_pool); 7085cfb1782SBart Van Assche } 7091dc7b1f1SChristoph Hellwig 7109566b054SBart Van Assche srp_destroy_qp(ch); 7111dc7b1f1SChristoph Hellwig ib_free_cq(ch->send_cq); 7121dc7b1f1SChristoph Hellwig ib_free_cq(ch->recv_cq); 713aef9ec39SRoland Dreier 714d92c0da7SBart Van Assche /* 715d92c0da7SBart Van Assche * Avoid that the SCSI error handler tries to use this channel after 716d92c0da7SBart Van Assche * it has been freed. The SCSI error handler can namely continue 717d92c0da7SBart Van Assche * trying to perform recovery actions after scsi_remove_host() 718d92c0da7SBart Van Assche * returned. 719d92c0da7SBart Van Assche */ 720d92c0da7SBart Van Assche ch->target = NULL; 721d92c0da7SBart Van Assche 722509c07bcSBart Van Assche ch->qp = NULL; 723509c07bcSBart Van Assche ch->send_cq = ch->recv_cq = NULL; 72473aa89edSIshai Rabinovitz 725509c07bcSBart Van Assche if (ch->rx_ring) { 7264d73f95fSBart Van Assche for (i = 0; i < target->queue_size; ++i) 727509c07bcSBart Van Assche srp_free_iu(target->srp_host, ch->rx_ring[i]); 728509c07bcSBart Van Assche kfree(ch->rx_ring); 729509c07bcSBart Van Assche ch->rx_ring = NULL; 7304d73f95fSBart Van Assche } 731509c07bcSBart Van Assche if (ch->tx_ring) { 7324d73f95fSBart Van Assche for (i = 0; i < target->queue_size; ++i) 733509c07bcSBart Van Assche srp_free_iu(target->srp_host, ch->tx_ring[i]); 734509c07bcSBart Van Assche kfree(ch->tx_ring); 735509c07bcSBart Van Assche ch->tx_ring = NULL; 7364d73f95fSBart Van Assche } 737aef9ec39SRoland Dreier } 738aef9ec39SRoland Dreier 739aef9ec39SRoland Dreier static void srp_path_rec_completion(int status, 740c2f8fc4eSDasaratharaman Chandramouli struct sa_path_rec *pathrec, 741509c07bcSBart Van Assche void *ch_ptr) 742aef9ec39SRoland Dreier { 743509c07bcSBart Van Assche struct srp_rdma_ch *ch = ch_ptr; 744509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 745aef9ec39SRoland Dreier 746509c07bcSBart Van Assche ch->status = status; 747aef9ec39SRoland Dreier if (status) 7487aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 7497aa54bd7SDavid Dillow PFX "Got failed path rec status %d\n", status); 750aef9ec39SRoland Dreier else 75119f31343SBart Van Assche ch->ib_cm.path = *pathrec; 752509c07bcSBart Van Assche complete(&ch->done); 753aef9ec39SRoland Dreier } 754aef9ec39SRoland Dreier 75519f31343SBart Van Assche static int srp_ib_lookup_path(struct srp_rdma_ch *ch) 756aef9ec39SRoland Dreier { 757509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 758c74ff750SBart Van Assche int ret; 759a702adceSBart Van Assche 76019f31343SBart Van Assche ch->ib_cm.path.numb_path = 1; 761aef9ec39SRoland Dreier 762509c07bcSBart Van Assche init_completion(&ch->done); 763aef9ec39SRoland Dreier 76419f31343SBart Van Assche ch->ib_cm.path_query_id = ib_sa_path_rec_get(&srp_sa_client, 76505321937SGreg Kroah-Hartman target->srp_host->srp_dev->dev, 766aef9ec39SRoland Dreier target->srp_host->port, 76719f31343SBart Van Assche &ch->ib_cm.path, 768247e020eSSean Hefty IB_SA_PATH_REC_SERVICE_ID | 769aef9ec39SRoland Dreier IB_SA_PATH_REC_DGID | 770aef9ec39SRoland Dreier IB_SA_PATH_REC_SGID | 771aef9ec39SRoland Dreier IB_SA_PATH_REC_NUMB_PATH | 772aef9ec39SRoland Dreier IB_SA_PATH_REC_PKEY, 773aef9ec39SRoland Dreier SRP_PATH_REC_TIMEOUT_MS, 774aef9ec39SRoland Dreier GFP_KERNEL, 775aef9ec39SRoland Dreier srp_path_rec_completion, 77619f31343SBart Van Assche ch, &ch->ib_cm.path_query); 777c74ff750SBart Van Assche if (ch->ib_cm.path_query_id < 0) 778c74ff750SBart Van Assche return ch->ib_cm.path_query_id; 779aef9ec39SRoland Dreier 780509c07bcSBart Van Assche ret = wait_for_completion_interruptible(&ch->done); 781a702adceSBart Van Assche if (ret < 0) 782c74ff750SBart Van Assche return ret; 783aef9ec39SRoland Dreier 784c74ff750SBart Van Assche if (ch->status < 0) 7857aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 78685769c6fSBart Van Assche PFX "Path record query failed: sgid %pI6, dgid %pI6, pkey %#04x, service_id %#16llx\n", 78719f31343SBart Van Assche ch->ib_cm.path.sgid.raw, ch->ib_cm.path.dgid.raw, 78819f31343SBart Van Assche be16_to_cpu(target->ib_cm.pkey), 78919f31343SBart Van Assche be64_to_cpu(target->ib_cm.service_id)); 790aef9ec39SRoland Dreier 791c74ff750SBart Van Assche return ch->status; 792aef9ec39SRoland Dreier } 793aef9ec39SRoland Dreier 79419f31343SBart Van Assche static int srp_rdma_lookup_path(struct srp_rdma_ch *ch) 79519f31343SBart Van Assche { 79619f31343SBart Van Assche struct srp_target_port *target = ch->target; 79719f31343SBart Van Assche int ret; 79819f31343SBart Van Assche 79919f31343SBart Van Assche init_completion(&ch->done); 80019f31343SBart Van Assche 80119f31343SBart Van Assche ret = rdma_resolve_route(ch->rdma_cm.cm_id, SRP_PATH_REC_TIMEOUT_MS); 80219f31343SBart Van Assche if (ret) 80319f31343SBart Van Assche return ret; 80419f31343SBart Van Assche 80519f31343SBart Van Assche wait_for_completion_interruptible(&ch->done); 80619f31343SBart Van Assche 80719f31343SBart Van Assche if (ch->status != 0) 80819f31343SBart Van Assche shost_printk(KERN_WARNING, target->scsi_host, 80919f31343SBart Van Assche PFX "Path resolution failed\n"); 81019f31343SBart Van Assche 81119f31343SBart Van Assche return ch->status; 81219f31343SBart Van Assche } 81319f31343SBart Van Assche 81419f31343SBart Van Assche static int srp_lookup_path(struct srp_rdma_ch *ch) 81519f31343SBart Van Assche { 81619f31343SBart Van Assche struct srp_target_port *target = ch->target; 81719f31343SBart Van Assche 81819f31343SBart Van Assche return target->using_rdma_cm ? srp_rdma_lookup_path(ch) : 81919f31343SBart Van Assche srp_ib_lookup_path(ch); 82019f31343SBart Van Assche } 82119f31343SBart Van Assche 8224c532d6cSBart Van Assche static u8 srp_get_subnet_timeout(struct srp_host *host) 8234c532d6cSBart Van Assche { 8244c532d6cSBart Van Assche struct ib_port_attr attr; 8254c532d6cSBart Van Assche int ret; 8264c532d6cSBart Van Assche u8 subnet_timeout = 18; 8274c532d6cSBart Van Assche 8284c532d6cSBart Van Assche ret = ib_query_port(host->srp_dev->dev, host->port, &attr); 8294c532d6cSBart Van Assche if (ret == 0) 8304c532d6cSBart Van Assche subnet_timeout = attr.subnet_timeout; 8314c532d6cSBart Van Assche 8324c532d6cSBart Van Assche if (unlikely(subnet_timeout < 15)) 8334c532d6cSBart Van Assche pr_warn("%s: subnet timeout %d may cause SRP login to fail.\n", 8344c532d6cSBart Van Assche dev_name(&host->srp_dev->dev->dev), subnet_timeout); 8354c532d6cSBart Van Assche 8364c532d6cSBart Van Assche return subnet_timeout; 8374c532d6cSBart Van Assche } 8384c532d6cSBart Van Assche 839513d5647SBart Van Assche static int srp_send_req(struct srp_rdma_ch *ch, uint32_t max_iu_len, 840513d5647SBart Van Assche bool multich) 841aef9ec39SRoland Dreier { 842509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 843aef9ec39SRoland Dreier struct { 84419f31343SBart Van Assche struct rdma_conn_param rdma_param; 84519f31343SBart Van Assche struct srp_login_req_rdma rdma_req; 84619f31343SBart Van Assche struct ib_cm_req_param ib_param; 84719f31343SBart Van Assche struct srp_login_req ib_req; 848aef9ec39SRoland Dreier } *req = NULL; 84948900a28SBart Van Assche char *ipi, *tpi; 850aef9ec39SRoland Dreier int status; 851aef9ec39SRoland Dreier 852aef9ec39SRoland Dreier req = kzalloc(sizeof *req, GFP_KERNEL); 853aef9ec39SRoland Dreier if (!req) 854aef9ec39SRoland Dreier return -ENOMEM; 855aef9ec39SRoland Dreier 85619f31343SBart Van Assche req->ib_param.flow_control = 1; 85719f31343SBart Van Assche req->ib_param.retry_count = target->tl_retry_count; 858aef9ec39SRoland Dreier 859aef9ec39SRoland Dreier /* 860aef9ec39SRoland Dreier * Pick some arbitrary defaults here; we could make these 861aef9ec39SRoland Dreier * module parameters if anyone cared about setting them. 862aef9ec39SRoland Dreier */ 86319f31343SBart Van Assche req->ib_param.responder_resources = 4; 86419f31343SBart Van Assche req->ib_param.rnr_retry_count = 7; 86519f31343SBart Van Assche req->ib_param.max_cm_retries = 15; 866aef9ec39SRoland Dreier 86719f31343SBart Van Assche req->ib_req.opcode = SRP_LOGIN_REQ; 86819f31343SBart Van Assche req->ib_req.tag = 0; 869513d5647SBart Van Assche req->ib_req.req_it_iu_len = cpu_to_be32(max_iu_len); 87019f31343SBart Van Assche req->ib_req.req_buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT | 871aef9ec39SRoland Dreier SRP_BUF_FORMAT_INDIRECT); 87219f31343SBart Van Assche req->ib_req.req_flags = (multich ? SRP_MULTICHAN_MULTI : 873d92c0da7SBart Van Assche SRP_MULTICHAN_SINGLE); 874882981f4SBart Van Assche if (srp_use_imm_data) { 875882981f4SBart Van Assche req->ib_req.req_flags |= SRP_IMMED_REQUESTED; 876882981f4SBart Van Assche req->ib_req.imm_data_offset = cpu_to_be16(SRP_IMM_DATA_OFFSET); 877882981f4SBart Van Assche } 87848900a28SBart Van Assche 87919f31343SBart Van Assche if (target->using_rdma_cm) { 88019f31343SBart Van Assche req->rdma_param.flow_control = req->ib_param.flow_control; 88119f31343SBart Van Assche req->rdma_param.responder_resources = 88219f31343SBart Van Assche req->ib_param.responder_resources; 88319f31343SBart Van Assche req->rdma_param.initiator_depth = req->ib_param.initiator_depth; 88419f31343SBart Van Assche req->rdma_param.retry_count = req->ib_param.retry_count; 88519f31343SBart Van Assche req->rdma_param.rnr_retry_count = req->ib_param.rnr_retry_count; 88619f31343SBart Van Assche req->rdma_param.private_data = &req->rdma_req; 88719f31343SBart Van Assche req->rdma_param.private_data_len = sizeof(req->rdma_req); 88819f31343SBart Van Assche 88919f31343SBart Van Assche req->rdma_req.opcode = req->ib_req.opcode; 89019f31343SBart Van Assche req->rdma_req.tag = req->ib_req.tag; 89119f31343SBart Van Assche req->rdma_req.req_it_iu_len = req->ib_req.req_it_iu_len; 89219f31343SBart Van Assche req->rdma_req.req_buf_fmt = req->ib_req.req_buf_fmt; 89319f31343SBart Van Assche req->rdma_req.req_flags = req->ib_req.req_flags; 894882981f4SBart Van Assche req->rdma_req.imm_data_offset = req->ib_req.imm_data_offset; 89519f31343SBart Van Assche 89619f31343SBart Van Assche ipi = req->rdma_req.initiator_port_id; 89719f31343SBart Van Assche tpi = req->rdma_req.target_port_id; 89819f31343SBart Van Assche } else { 89948900a28SBart Van Assche u8 subnet_timeout; 90048900a28SBart Van Assche 90148900a28SBart Van Assche subnet_timeout = srp_get_subnet_timeout(target->srp_host); 90248900a28SBart Van Assche 90319f31343SBart Van Assche req->ib_param.primary_path = &ch->ib_cm.path; 90419f31343SBart Van Assche req->ib_param.alternate_path = NULL; 90519f31343SBart Van Assche req->ib_param.service_id = target->ib_cm.service_id; 90619f31343SBart Van Assche get_random_bytes(&req->ib_param.starting_psn, 4); 90719f31343SBart Van Assche req->ib_param.starting_psn &= 0xffffff; 90819f31343SBart Van Assche req->ib_param.qp_num = ch->qp->qp_num; 90919f31343SBart Van Assche req->ib_param.qp_type = ch->qp->qp_type; 91019f31343SBart Van Assche req->ib_param.local_cm_response_timeout = subnet_timeout + 2; 91119f31343SBart Van Assche req->ib_param.remote_cm_response_timeout = subnet_timeout + 2; 91219f31343SBart Van Assche req->ib_param.private_data = &req->ib_req; 91319f31343SBart Van Assche req->ib_param.private_data_len = sizeof(req->ib_req); 91448900a28SBart Van Assche 91519f31343SBart Van Assche ipi = req->ib_req.initiator_port_id; 91619f31343SBart Van Assche tpi = req->ib_req.target_port_id; 91748900a28SBart Van Assche } 91848900a28SBart Van Assche 9190c0450dbSRamachandra K /* 9200c0450dbSRamachandra K * In the published SRP specification (draft rev. 16a), the 9210c0450dbSRamachandra K * port identifier format is 8 bytes of ID extension followed 9220c0450dbSRamachandra K * by 8 bytes of GUID. Older drafts put the two halves in the 9230c0450dbSRamachandra K * opposite order, so that the GUID comes first. 9240c0450dbSRamachandra K * 9250c0450dbSRamachandra K * Targets conforming to these obsolete drafts can be 9260c0450dbSRamachandra K * recognized by the I/O Class they report. 9270c0450dbSRamachandra K */ 9280c0450dbSRamachandra K if (target->io_class == SRP_REV10_IB_IO_CLASS) { 92948900a28SBart Van Assche memcpy(ipi, &target->sgid.global.interface_id, 8); 93048900a28SBart Van Assche memcpy(ipi + 8, &target->initiator_ext, 8); 93148900a28SBart Van Assche memcpy(tpi, &target->ioc_guid, 8); 93248900a28SBart Van Assche memcpy(tpi + 8, &target->id_ext, 8); 9330c0450dbSRamachandra K } else { 93448900a28SBart Van Assche memcpy(ipi, &target->initiator_ext, 8); 93548900a28SBart Van Assche memcpy(ipi + 8, &target->sgid.global.interface_id, 8); 93648900a28SBart Van Assche memcpy(tpi, &target->id_ext, 8); 93748900a28SBart Van Assche memcpy(tpi + 8, &target->ioc_guid, 8); 9380c0450dbSRamachandra K } 9390c0450dbSRamachandra K 940aef9ec39SRoland Dreier /* 941aef9ec39SRoland Dreier * Topspin/Cisco SRP targets will reject our login unless we 94201cb9bcbSIshai Rabinovitz * zero out the first 8 bytes of our initiator port ID and set 94301cb9bcbSIshai Rabinovitz * the second 8 bytes to the local node GUID. 944aef9ec39SRoland Dreier */ 9455d7cbfd6SRoland Dreier if (srp_target_is_topspin(target)) { 9467aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, target->scsi_host, 9477aa54bd7SDavid Dillow PFX "Topspin/Cisco initiator port ID workaround " 948aef9ec39SRoland Dreier "activated for target GUID %016llx\n", 94945c37cadSBart Van Assche be64_to_cpu(target->ioc_guid)); 95048900a28SBart Van Assche memset(ipi, 0, 8); 95148900a28SBart Van Assche memcpy(ipi + 8, &target->srp_host->srp_dev->dev->node_guid, 8); 952aef9ec39SRoland Dreier } 953aef9ec39SRoland Dreier 95419f31343SBart Van Assche if (target->using_rdma_cm) 95519f31343SBart Van Assche status = rdma_connect(ch->rdma_cm.cm_id, &req->rdma_param); 95619f31343SBart Van Assche else 95719f31343SBart Van Assche status = ib_send_cm_req(ch->ib_cm.cm_id, &req->ib_param); 958aef9ec39SRoland Dreier 959aef9ec39SRoland Dreier kfree(req); 960aef9ec39SRoland Dreier 961aef9ec39SRoland Dreier return status; 962aef9ec39SRoland Dreier } 963aef9ec39SRoland Dreier 964ef6c49d8SBart Van Assche static bool srp_queue_remove_work(struct srp_target_port *target) 965ef6c49d8SBart Van Assche { 966ef6c49d8SBart Van Assche bool changed = false; 967ef6c49d8SBart Van Assche 968ef6c49d8SBart Van Assche spin_lock_irq(&target->lock); 969ef6c49d8SBart Van Assche if (target->state != SRP_TARGET_REMOVED) { 970ef6c49d8SBart Van Assche target->state = SRP_TARGET_REMOVED; 971ef6c49d8SBart Van Assche changed = true; 972ef6c49d8SBart Van Assche } 973ef6c49d8SBart Van Assche spin_unlock_irq(&target->lock); 974ef6c49d8SBart Van Assche 975ef6c49d8SBart Van Assche if (changed) 976bcc05910SBart Van Assche queue_work(srp_remove_wq, &target->remove_work); 977ef6c49d8SBart Van Assche 978ef6c49d8SBart Van Assche return changed; 979ef6c49d8SBart Van Assche } 980ef6c49d8SBart Van Assche 981aef9ec39SRoland Dreier static void srp_disconnect_target(struct srp_target_port *target) 982aef9ec39SRoland Dreier { 983d92c0da7SBart Van Assche struct srp_rdma_ch *ch; 98419f31343SBart Van Assche int i, ret; 985509c07bcSBart Van Assche 986aef9ec39SRoland Dreier /* XXX should send SRP_I_LOGOUT request */ 987aef9ec39SRoland Dreier 988d92c0da7SBart Van Assche for (i = 0; i < target->ch_count; i++) { 989d92c0da7SBart Van Assche ch = &target->ch[i]; 990c014c8cdSBart Van Assche ch->connected = false; 99119f31343SBart Van Assche ret = 0; 99219f31343SBart Van Assche if (target->using_rdma_cm) { 99319f31343SBart Van Assche if (ch->rdma_cm.cm_id) 99419f31343SBart Van Assche rdma_disconnect(ch->rdma_cm.cm_id); 99519f31343SBart Van Assche } else { 99619f31343SBart Van Assche if (ch->ib_cm.cm_id) 99719f31343SBart Van Assche ret = ib_send_cm_dreq(ch->ib_cm.cm_id, 99819f31343SBart Van Assche NULL, 0); 99919f31343SBart Van Assche } 100019f31343SBart Van Assche if (ret < 0) { 10017aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, target->scsi_host, 10027aa54bd7SDavid Dillow PFX "Sending CM DREQ failed\n"); 1003aef9ec39SRoland Dreier } 1004294c875aSBart Van Assche } 1005294c875aSBart Van Assche } 1006aef9ec39SRoland Dreier 1007509c07bcSBart Van Assche static void srp_free_req_data(struct srp_target_port *target, 1008509c07bcSBart Van Assche struct srp_rdma_ch *ch) 10098f26c9ffSDavid Dillow { 10105cfb1782SBart Van Assche struct srp_device *dev = target->srp_host->srp_dev; 10115cfb1782SBart Van Assche struct ib_device *ibdev = dev->dev; 10128f26c9ffSDavid Dillow struct srp_request *req; 10138f26c9ffSDavid Dillow int i; 10148f26c9ffSDavid Dillow 101547513cf4SBart Van Assche if (!ch->req_ring) 10164d73f95fSBart Van Assche return; 10174d73f95fSBart Van Assche 10184d73f95fSBart Van Assche for (i = 0; i < target->req_ring_size; ++i) { 1019509c07bcSBart Van Assche req = &ch->req_ring[i]; 10209a21be53SSagi Grimberg if (dev->use_fast_reg) { 10215cfb1782SBart Van Assche kfree(req->fr_list); 10229a21be53SSagi Grimberg } else { 10238f26c9ffSDavid Dillow kfree(req->fmr_list); 10248f26c9ffSDavid Dillow kfree(req->map_page); 10259a21be53SSagi Grimberg } 1026c07d424dSDavid Dillow if (req->indirect_dma_addr) { 1027c07d424dSDavid Dillow ib_dma_unmap_single(ibdev, req->indirect_dma_addr, 1028c07d424dSDavid Dillow target->indirect_size, 1029c07d424dSDavid Dillow DMA_TO_DEVICE); 1030c07d424dSDavid Dillow } 1031c07d424dSDavid Dillow kfree(req->indirect_desc); 10328f26c9ffSDavid Dillow } 10334d73f95fSBart Van Assche 1034509c07bcSBart Van Assche kfree(ch->req_ring); 1035509c07bcSBart Van Assche ch->req_ring = NULL; 10368f26c9ffSDavid Dillow } 10378f26c9ffSDavid Dillow 1038509c07bcSBart Van Assche static int srp_alloc_req_data(struct srp_rdma_ch *ch) 1039b81d00bdSBart Van Assche { 1040509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 1041b81d00bdSBart Van Assche struct srp_device *srp_dev = target->srp_host->srp_dev; 1042b81d00bdSBart Van Assche struct ib_device *ibdev = srp_dev->dev; 1043b81d00bdSBart Van Assche struct srp_request *req; 10445cfb1782SBart Van Assche void *mr_list; 1045b81d00bdSBart Van Assche dma_addr_t dma_addr; 1046b81d00bdSBart Van Assche int i, ret = -ENOMEM; 1047b81d00bdSBart Van Assche 1048509c07bcSBart Van Assche ch->req_ring = kcalloc(target->req_ring_size, sizeof(*ch->req_ring), 1049509c07bcSBart Van Assche GFP_KERNEL); 1050509c07bcSBart Van Assche if (!ch->req_ring) 10514d73f95fSBart Van Assche goto out; 10524d73f95fSBart Van Assche 10534d73f95fSBart Van Assche for (i = 0; i < target->req_ring_size; ++i) { 1054509c07bcSBart Van Assche req = &ch->req_ring[i]; 10556da2ec56SKees Cook mr_list = kmalloc_array(target->mr_per_cmd, sizeof(void *), 1056b81d00bdSBart Van Assche GFP_KERNEL); 10575cfb1782SBart Van Assche if (!mr_list) 10585cfb1782SBart Van Assche goto out; 10599a21be53SSagi Grimberg if (srp_dev->use_fast_reg) { 10605cfb1782SBart Van Assche req->fr_list = mr_list; 10619a21be53SSagi Grimberg } else { 10625cfb1782SBart Van Assche req->fmr_list = mr_list; 10636da2ec56SKees Cook req->map_page = kmalloc_array(srp_dev->max_pages_per_mr, 10646da2ec56SKees Cook sizeof(void *), 10656da2ec56SKees Cook GFP_KERNEL); 10665cfb1782SBart Van Assche if (!req->map_page) 10675cfb1782SBart Van Assche goto out; 10689a21be53SSagi Grimberg } 1069b81d00bdSBart Van Assche req->indirect_desc = kmalloc(target->indirect_size, GFP_KERNEL); 10705cfb1782SBart Van Assche if (!req->indirect_desc) 1071b81d00bdSBart Van Assche goto out; 1072b81d00bdSBart Van Assche 1073b81d00bdSBart Van Assche dma_addr = ib_dma_map_single(ibdev, req->indirect_desc, 1074b81d00bdSBart Van Assche target->indirect_size, 1075b81d00bdSBart Van Assche DMA_TO_DEVICE); 1076b81d00bdSBart Van Assche if (ib_dma_mapping_error(ibdev, dma_addr)) 1077b81d00bdSBart Van Assche goto out; 1078b81d00bdSBart Van Assche 1079b81d00bdSBart Van Assche req->indirect_dma_addr = dma_addr; 1080b81d00bdSBart Van Assche } 1081b81d00bdSBart Van Assche ret = 0; 1082b81d00bdSBart Van Assche 1083b81d00bdSBart Van Assche out: 1084b81d00bdSBart Van Assche return ret; 1085b81d00bdSBart Van Assche } 1086b81d00bdSBart Van Assche 1087683b159aSBart Van Assche /** 1088683b159aSBart Van Assche * srp_del_scsi_host_attr() - Remove attributes defined in the host template. 1089683b159aSBart Van Assche * @shost: SCSI host whose attributes to remove from sysfs. 1090683b159aSBart Van Assche * 1091683b159aSBart Van Assche * Note: Any attributes defined in the host template and that did not exist 1092683b159aSBart Van Assche * before invocation of this function will be ignored. 1093683b159aSBart Van Assche */ 1094683b159aSBart Van Assche static void srp_del_scsi_host_attr(struct Scsi_Host *shost) 1095683b159aSBart Van Assche { 1096683b159aSBart Van Assche struct device_attribute **attr; 1097683b159aSBart Van Assche 1098683b159aSBart Van Assche for (attr = shost->hostt->shost_attrs; attr && *attr; ++attr) 1099683b159aSBart Van Assche device_remove_file(&shost->shost_dev, *attr); 1100683b159aSBart Van Assche } 1101683b159aSBart Van Assche 1102ee12d6a8SBart Van Assche static void srp_remove_target(struct srp_target_port *target) 1103ee12d6a8SBart Van Assche { 1104d92c0da7SBart Van Assche struct srp_rdma_ch *ch; 1105d92c0da7SBart Van Assche int i; 1106509c07bcSBart Van Assche 1107ef6c49d8SBart Van Assche WARN_ON_ONCE(target->state != SRP_TARGET_REMOVED); 1108ef6c49d8SBart Van Assche 1109ee12d6a8SBart Van Assche srp_del_scsi_host_attr(target->scsi_host); 11109dd69a60SBart Van Assche srp_rport_get(target->rport); 1111ee12d6a8SBart Van Assche srp_remove_host(target->scsi_host); 1112ee12d6a8SBart Van Assche scsi_remove_host(target->scsi_host); 111393079162SBart Van Assche srp_stop_rport_timers(target->rport); 1114ef6c49d8SBart Van Assche srp_disconnect_target(target); 111519f31343SBart Van Assche kobj_ns_drop(KOBJ_NS_TYPE_NET, target->net); 1116d92c0da7SBart Van Assche for (i = 0; i < target->ch_count; i++) { 1117d92c0da7SBart Van Assche ch = &target->ch[i]; 1118509c07bcSBart Van Assche srp_free_ch_ib(target, ch); 1119d92c0da7SBart Van Assche } 1120c1120f89SBart Van Assche cancel_work_sync(&target->tl_err_work); 11219dd69a60SBart Van Assche srp_rport_put(target->rport); 1122d92c0da7SBart Van Assche for (i = 0; i < target->ch_count; i++) { 1123d92c0da7SBart Van Assche ch = &target->ch[i]; 1124509c07bcSBart Van Assche srp_free_req_data(target, ch); 1125d92c0da7SBart Van Assche } 1126d92c0da7SBart Van Assche kfree(target->ch); 1127d92c0da7SBart Van Assche target->ch = NULL; 112865d7dd2fSVu Pham 112965d7dd2fSVu Pham spin_lock(&target->srp_host->target_lock); 113065d7dd2fSVu Pham list_del(&target->list); 113165d7dd2fSVu Pham spin_unlock(&target->srp_host->target_lock); 113265d7dd2fSVu Pham 1133ee12d6a8SBart Van Assche scsi_host_put(target->scsi_host); 1134ee12d6a8SBart Van Assche } 1135ee12d6a8SBart Van Assche 1136c4028958SDavid Howells static void srp_remove_work(struct work_struct *work) 1137aef9ec39SRoland Dreier { 1138c4028958SDavid Howells struct srp_target_port *target = 1139ef6c49d8SBart Van Assche container_of(work, struct srp_target_port, remove_work); 1140aef9ec39SRoland Dreier 1141ef6c49d8SBart Van Assche WARN_ON_ONCE(target->state != SRP_TARGET_REMOVED); 1142aef9ec39SRoland Dreier 114396fc248aSBart Van Assche srp_remove_target(target); 1144aef9ec39SRoland Dreier } 1145aef9ec39SRoland Dreier 1146dc1bdbd9SBart Van Assche static void srp_rport_delete(struct srp_rport *rport) 1147dc1bdbd9SBart Van Assche { 1148dc1bdbd9SBart Van Assche struct srp_target_port *target = rport->lld_data; 1149dc1bdbd9SBart Van Assche 1150dc1bdbd9SBart Van Assche srp_queue_remove_work(target); 1151dc1bdbd9SBart Van Assche } 1152dc1bdbd9SBart Van Assche 1153c014c8cdSBart Van Assche /** 1154c014c8cdSBart Van Assche * srp_connected_ch() - number of connected channels 1155c014c8cdSBart Van Assche * @target: SRP target port. 1156c014c8cdSBart Van Assche */ 1157c014c8cdSBart Van Assche static int srp_connected_ch(struct srp_target_port *target) 1158c014c8cdSBart Van Assche { 1159c014c8cdSBart Van Assche int i, c = 0; 1160c014c8cdSBart Van Assche 1161c014c8cdSBart Van Assche for (i = 0; i < target->ch_count; i++) 1162c014c8cdSBart Van Assche c += target->ch[i].connected; 1163c014c8cdSBart Van Assche 1164c014c8cdSBart Van Assche return c; 1165c014c8cdSBart Van Assche } 1166c014c8cdSBart Van Assche 1167513d5647SBart Van Assche static int srp_connect_ch(struct srp_rdma_ch *ch, uint32_t max_iu_len, 1168513d5647SBart Van Assche bool multich) 1169aef9ec39SRoland Dreier { 1170509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 1171aef9ec39SRoland Dreier int ret; 1172aef9ec39SRoland Dreier 1173c014c8cdSBart Van Assche WARN_ON_ONCE(!multich && srp_connected_ch(target) > 0); 1174294c875aSBart Van Assche 1175509c07bcSBart Van Assche ret = srp_lookup_path(ch); 1176aef9ec39SRoland Dreier if (ret) 11774d59ad29SBart Van Assche goto out; 1178aef9ec39SRoland Dreier 1179aef9ec39SRoland Dreier while (1) { 1180509c07bcSBart Van Assche init_completion(&ch->done); 1181513d5647SBart Van Assche ret = srp_send_req(ch, max_iu_len, multich); 1182aef9ec39SRoland Dreier if (ret) 11834d59ad29SBart Van Assche goto out; 1184509c07bcSBart Van Assche ret = wait_for_completion_interruptible(&ch->done); 1185a702adceSBart Van Assche if (ret < 0) 11864d59ad29SBart Van Assche goto out; 1187aef9ec39SRoland Dreier 1188aef9ec39SRoland Dreier /* 1189aef9ec39SRoland Dreier * The CM event handling code will set status to 1190aef9ec39SRoland Dreier * SRP_PORT_REDIRECT if we get a port redirect REJ 1191aef9ec39SRoland Dreier * back, or SRP_DLID_REDIRECT if we get a lid/qp 1192aef9ec39SRoland Dreier * redirect REJ back. 1193aef9ec39SRoland Dreier */ 11944d59ad29SBart Van Assche ret = ch->status; 11954d59ad29SBart Van Assche switch (ret) { 1196aef9ec39SRoland Dreier case 0: 1197c014c8cdSBart Van Assche ch->connected = true; 11984d59ad29SBart Van Assche goto out; 1199aef9ec39SRoland Dreier 1200aef9ec39SRoland Dreier case SRP_PORT_REDIRECT: 1201509c07bcSBart Van Assche ret = srp_lookup_path(ch); 1202aef9ec39SRoland Dreier if (ret) 12034d59ad29SBart Van Assche goto out; 1204aef9ec39SRoland Dreier break; 1205aef9ec39SRoland Dreier 1206aef9ec39SRoland Dreier case SRP_DLID_REDIRECT: 1207aef9ec39SRoland Dreier break; 1208aef9ec39SRoland Dreier 12099fe4bcf4SDavid Dillow case SRP_STALE_CONN: 12109fe4bcf4SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX 12119fe4bcf4SDavid Dillow "giving up on stale connection\n"); 12124d59ad29SBart Van Assche ret = -ECONNRESET; 12134d59ad29SBart Van Assche goto out; 12149fe4bcf4SDavid Dillow 1215aef9ec39SRoland Dreier default: 12164d59ad29SBart Van Assche goto out; 1217aef9ec39SRoland Dreier } 1218aef9ec39SRoland Dreier } 12194d59ad29SBart Van Assche 12204d59ad29SBart Van Assche out: 12214d59ad29SBart Van Assche return ret <= 0 ? ret : -ENODEV; 1222aef9ec39SRoland Dreier } 1223aef9ec39SRoland Dreier 12241dc7b1f1SChristoph Hellwig static void srp_inv_rkey_err_done(struct ib_cq *cq, struct ib_wc *wc) 12251dc7b1f1SChristoph Hellwig { 12261dc7b1f1SChristoph Hellwig srp_handle_qp_err(cq, wc, "INV RKEY"); 12271dc7b1f1SChristoph Hellwig } 12281dc7b1f1SChristoph Hellwig 12291dc7b1f1SChristoph Hellwig static int srp_inv_rkey(struct srp_request *req, struct srp_rdma_ch *ch, 12301dc7b1f1SChristoph Hellwig u32 rkey) 12315cfb1782SBart Van Assche { 12325cfb1782SBart Van Assche struct ib_send_wr wr = { 12335cfb1782SBart Van Assche .opcode = IB_WR_LOCAL_INV, 12345cfb1782SBart Van Assche .next = NULL, 12355cfb1782SBart Van Assche .num_sge = 0, 12365cfb1782SBart Van Assche .send_flags = 0, 12375cfb1782SBart Van Assche .ex.invalidate_rkey = rkey, 12385cfb1782SBart Van Assche }; 12395cfb1782SBart Van Assche 12401dc7b1f1SChristoph Hellwig wr.wr_cqe = &req->reg_cqe; 12411dc7b1f1SChristoph Hellwig req->reg_cqe.done = srp_inv_rkey_err_done; 124271347b0cSBart Van Assche return ib_post_send(ch->qp, &wr, NULL); 12435cfb1782SBart Van Assche } 12445cfb1782SBart Van Assche 1245d945e1dfSRoland Dreier static void srp_unmap_data(struct scsi_cmnd *scmnd, 1246509c07bcSBart Van Assche struct srp_rdma_ch *ch, 1247d945e1dfSRoland Dreier struct srp_request *req) 1248d945e1dfSRoland Dreier { 1249509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 12505cfb1782SBart Van Assche struct srp_device *dev = target->srp_host->srp_dev; 12515cfb1782SBart Van Assche struct ib_device *ibdev = dev->dev; 12525cfb1782SBart Van Assche int i, res; 12538f26c9ffSDavid Dillow 1254bb350d1dSFUJITA Tomonori if (!scsi_sglist(scmnd) || 1255d945e1dfSRoland Dreier (scmnd->sc_data_direction != DMA_TO_DEVICE && 1256d945e1dfSRoland Dreier scmnd->sc_data_direction != DMA_FROM_DEVICE)) 1257d945e1dfSRoland Dreier return; 1258d945e1dfSRoland Dreier 12595cfb1782SBart Van Assche if (dev->use_fast_reg) { 12605cfb1782SBart Van Assche struct srp_fr_desc **pfr; 12615cfb1782SBart Van Assche 12625cfb1782SBart Van Assche for (i = req->nmdesc, pfr = req->fr_list; i > 0; i--, pfr++) { 12631dc7b1f1SChristoph Hellwig res = srp_inv_rkey(req, ch, (*pfr)->mr->rkey); 12645cfb1782SBart Van Assche if (res < 0) { 12655cfb1782SBart Van Assche shost_printk(KERN_ERR, target->scsi_host, PFX 12665cfb1782SBart Van Assche "Queueing INV WR for rkey %#x failed (%d)\n", 12675cfb1782SBart Van Assche (*pfr)->mr->rkey, res); 12685cfb1782SBart Van Assche queue_work(system_long_wq, 12695cfb1782SBart Van Assche &target->tl_err_work); 12705cfb1782SBart Van Assche } 12715cfb1782SBart Van Assche } 12725cfb1782SBart Van Assche if (req->nmdesc) 1273509c07bcSBart Van Assche srp_fr_pool_put(ch->fr_pool, req->fr_list, 12745cfb1782SBart Van Assche req->nmdesc); 1275002f1567SBart Van Assche } else if (dev->use_fmr) { 12765cfb1782SBart Van Assche struct ib_pool_fmr **pfmr; 12775cfb1782SBart Van Assche 12785cfb1782SBart Van Assche for (i = req->nmdesc, pfmr = req->fmr_list; i > 0; i--, pfmr++) 12795cfb1782SBart Van Assche ib_fmr_pool_unmap(*pfmr); 12805cfb1782SBart Van Assche } 1281f5358a17SRoland Dreier 12828f26c9ffSDavid Dillow ib_dma_unmap_sg(ibdev, scsi_sglist(scmnd), scsi_sg_count(scmnd), 12838f26c9ffSDavid Dillow scmnd->sc_data_direction); 1284d945e1dfSRoland Dreier } 1285d945e1dfSRoland Dreier 128622032991SBart Van Assche /** 128722032991SBart Van Assche * srp_claim_req - Take ownership of the scmnd associated with a request. 1288509c07bcSBart Van Assche * @ch: SRP RDMA channel. 128922032991SBart Van Assche * @req: SRP request. 1290b3fe628dSBart Van Assche * @sdev: If not NULL, only take ownership for this SCSI device. 129122032991SBart Van Assche * @scmnd: If NULL, take ownership of @req->scmnd. If not NULL, only take 129222032991SBart Van Assche * ownership of @req->scmnd if it equals @scmnd. 129322032991SBart Van Assche * 129422032991SBart Van Assche * Return value: 129522032991SBart Van Assche * Either NULL or a pointer to the SCSI command the caller became owner of. 129622032991SBart Van Assche */ 1297509c07bcSBart Van Assche static struct scsi_cmnd *srp_claim_req(struct srp_rdma_ch *ch, 129822032991SBart Van Assche struct srp_request *req, 1299b3fe628dSBart Van Assche struct scsi_device *sdev, 130022032991SBart Van Assche struct scsi_cmnd *scmnd) 1301526b4caaSIshai Rabinovitz { 130294a9174cSBart Van Assche unsigned long flags; 130394a9174cSBart Van Assche 1304509c07bcSBart Van Assche spin_lock_irqsave(&ch->lock, flags); 1305b3fe628dSBart Van Assche if (req->scmnd && 1306b3fe628dSBart Van Assche (!sdev || req->scmnd->device == sdev) && 1307b3fe628dSBart Van Assche (!scmnd || req->scmnd == scmnd)) { 130822032991SBart Van Assche scmnd = req->scmnd; 130922032991SBart Van Assche req->scmnd = NULL; 131022032991SBart Van Assche } else { 131122032991SBart Van Assche scmnd = NULL; 131222032991SBart Van Assche } 1313509c07bcSBart Van Assche spin_unlock_irqrestore(&ch->lock, flags); 131422032991SBart Van Assche 131522032991SBart Van Assche return scmnd; 131622032991SBart Van Assche } 131722032991SBart Van Assche 131822032991SBart Van Assche /** 13196ec2ba02SBart Van Assche * srp_free_req() - Unmap data and adjust ch->req_lim. 1320509c07bcSBart Van Assche * @ch: SRP RDMA channel. 1321af24663bSBart Van Assche * @req: Request to be freed. 1322af24663bSBart Van Assche * @scmnd: SCSI command associated with @req. 1323af24663bSBart Van Assche * @req_lim_delta: Amount to be added to @target->req_lim. 132422032991SBart Van Assche */ 1325509c07bcSBart Van Assche static void srp_free_req(struct srp_rdma_ch *ch, struct srp_request *req, 1326509c07bcSBart Van Assche struct scsi_cmnd *scmnd, s32 req_lim_delta) 132722032991SBart Van Assche { 132822032991SBart Van Assche unsigned long flags; 132922032991SBart Van Assche 1330509c07bcSBart Van Assche srp_unmap_data(scmnd, ch, req); 133122032991SBart Van Assche 1332509c07bcSBart Van Assche spin_lock_irqsave(&ch->lock, flags); 1333509c07bcSBart Van Assche ch->req_lim += req_lim_delta; 1334509c07bcSBart Van Assche spin_unlock_irqrestore(&ch->lock, flags); 1335526b4caaSIshai Rabinovitz } 1336526b4caaSIshai Rabinovitz 1337509c07bcSBart Van Assche static void srp_finish_req(struct srp_rdma_ch *ch, struct srp_request *req, 1338509c07bcSBart Van Assche struct scsi_device *sdev, int result) 1339526b4caaSIshai Rabinovitz { 1340509c07bcSBart Van Assche struct scsi_cmnd *scmnd = srp_claim_req(ch, req, sdev, NULL); 134122032991SBart Van Assche 134222032991SBart Van Assche if (scmnd) { 1343509c07bcSBart Van Assche srp_free_req(ch, req, scmnd, 0); 1344ed9b2264SBart Van Assche scmnd->result = result; 134522032991SBart Van Assche scmnd->scsi_done(scmnd); 134622032991SBart Van Assche } 1347526b4caaSIshai Rabinovitz } 1348526b4caaSIshai Rabinovitz 1349ed9b2264SBart Van Assche static void srp_terminate_io(struct srp_rport *rport) 1350aef9ec39SRoland Dreier { 1351ed9b2264SBart Van Assche struct srp_target_port *target = rport->lld_data; 1352d92c0da7SBart Van Assche struct srp_rdma_ch *ch; 1353d92c0da7SBart Van Assche int i, j; 1354aef9ec39SRoland Dreier 1355d92c0da7SBart Van Assche for (i = 0; i < target->ch_count; i++) { 1356d92c0da7SBart Van Assche ch = &target->ch[i]; 1357509c07bcSBart Van Assche 1358d92c0da7SBart Van Assche for (j = 0; j < target->req_ring_size; ++j) { 1359d92c0da7SBart Van Assche struct srp_request *req = &ch->req_ring[j]; 1360d92c0da7SBart Van Assche 1361d92c0da7SBart Van Assche srp_finish_req(ch, req, NULL, 1362d92c0da7SBart Van Assche DID_TRANSPORT_FAILFAST << 16); 1363d92c0da7SBart Van Assche } 1364ed9b2264SBart Van Assche } 1365ed9b2264SBart Van Assche } 1366ed9b2264SBart Van Assche 1367513d5647SBart Van Assche /* Calculate maximum initiator to target information unit length. */ 1368*b2e872f4SHonggang Li static uint32_t srp_max_it_iu_len(int cmd_sg_cnt, bool use_imm_data, 1369*b2e872f4SHonggang Li uint32_t max_it_iu_size) 1370513d5647SBart Van Assche { 1371513d5647SBart Van Assche uint32_t max_iu_len = sizeof(struct srp_cmd) + SRP_MAX_ADD_CDB_LEN + 1372513d5647SBart Van Assche sizeof(struct srp_indirect_buf) + 1373513d5647SBart Van Assche cmd_sg_cnt * sizeof(struct srp_direct_buf); 1374513d5647SBart Van Assche 1375882981f4SBart Van Assche if (use_imm_data) 1376882981f4SBart Van Assche max_iu_len = max(max_iu_len, SRP_IMM_DATA_OFFSET + 1377882981f4SBart Van Assche srp_max_imm_data); 1378882981f4SBart Van Assche 1379*b2e872f4SHonggang Li if (max_it_iu_size) 1380*b2e872f4SHonggang Li max_iu_len = min(max_iu_len, max_it_iu_size); 1381*b2e872f4SHonggang Li 1382*b2e872f4SHonggang Li pr_debug("max_iu_len = %d\n", max_iu_len); 1383*b2e872f4SHonggang Li 1384513d5647SBart Van Assche return max_iu_len; 1385513d5647SBart Van Assche } 1386513d5647SBart Van Assche 1387ed9b2264SBart Van Assche /* 1388ed9b2264SBart Van Assche * It is up to the caller to ensure that srp_rport_reconnect() calls are 1389ed9b2264SBart Van Assche * serialized and that no concurrent srp_queuecommand(), srp_abort(), 1390ed9b2264SBart Van Assche * srp_reset_device() or srp_reset_host() calls will occur while this function 1391ed9b2264SBart Van Assche * is in progress. One way to realize that is not to call this function 1392ed9b2264SBart Van Assche * directly but to call srp_reconnect_rport() instead since that last function 1393ed9b2264SBart Van Assche * serializes calls of this function via rport->mutex and also blocks 1394ed9b2264SBart Van Assche * srp_queuecommand() calls before invoking this function. 1395ed9b2264SBart Van Assche */ 1396ed9b2264SBart Van Assche static int srp_rport_reconnect(struct srp_rport *rport) 1397ed9b2264SBart Van Assche { 1398ed9b2264SBart Van Assche struct srp_target_port *target = rport->lld_data; 1399d92c0da7SBart Van Assche struct srp_rdma_ch *ch; 1400882981f4SBart Van Assche uint32_t max_iu_len = srp_max_it_iu_len(target->cmd_sg_cnt, 1401*b2e872f4SHonggang Li srp_use_imm_data, 1402*b2e872f4SHonggang Li target->max_it_iu_size); 1403d92c0da7SBart Van Assche int i, j, ret = 0; 1404d92c0da7SBart Van Assche bool multich = false; 140509be70a2SBart Van Assche 1406aef9ec39SRoland Dreier srp_disconnect_target(target); 140734aa654eSBart Van Assche 140834aa654eSBart Van Assche if (target->state == SRP_TARGET_SCANNING) 140934aa654eSBart Van Assche return -ENODEV; 141034aa654eSBart Van Assche 1411aef9ec39SRoland Dreier /* 1412c7c4e7ffSBart Van Assche * Now get a new local CM ID so that we avoid confusing the target in 1413c7c4e7ffSBart Van Assche * case things are really fouled up. Doing so also ensures that all CM 1414c7c4e7ffSBart Van Assche * callbacks will have finished before a new QP is allocated. 1415aef9ec39SRoland Dreier */ 1416d92c0da7SBart Van Assche for (i = 0; i < target->ch_count; i++) { 1417d92c0da7SBart Van Assche ch = &target->ch[i]; 1418d92c0da7SBart Van Assche ret += srp_new_cm_id(ch); 1419d92c0da7SBart Van Assche } 1420d92c0da7SBart Van Assche for (i = 0; i < target->ch_count; i++) { 1421d92c0da7SBart Van Assche ch = &target->ch[i]; 1422d92c0da7SBart Van Assche for (j = 0; j < target->req_ring_size; ++j) { 1423d92c0da7SBart Van Assche struct srp_request *req = &ch->req_ring[j]; 1424509c07bcSBart Van Assche 1425509c07bcSBart Van Assche srp_finish_req(ch, req, NULL, DID_RESET << 16); 1426536ae14eSBart Van Assche } 1427d92c0da7SBart Van Assche } 1428d92c0da7SBart Van Assche for (i = 0; i < target->ch_count; i++) { 1429d92c0da7SBart Van Assche ch = &target->ch[i]; 14305cfb1782SBart Van Assche /* 14315cfb1782SBart Van Assche * Whether or not creating a new CM ID succeeded, create a new 1432d92c0da7SBart Van Assche * QP. This guarantees that all completion callback function 1433d92c0da7SBart Van Assche * invocations have finished before request resetting starts. 14345cfb1782SBart Van Assche */ 1435509c07bcSBart Van Assche ret += srp_create_ch_ib(ch); 14365cfb1782SBart Van Assche 1437509c07bcSBart Van Assche INIT_LIST_HEAD(&ch->free_tx); 1438d92c0da7SBart Van Assche for (j = 0; j < target->queue_size; ++j) 1439d92c0da7SBart Van Assche list_add(&ch->tx_ring[j]->list, &ch->free_tx); 1440d92c0da7SBart Van Assche } 14418de9fe3aSBart Van Assche 14428de9fe3aSBart Van Assche target->qp_in_error = false; 14438de9fe3aSBart Van Assche 1444d92c0da7SBart Van Assche for (i = 0; i < target->ch_count; i++) { 1445d92c0da7SBart Van Assche ch = &target->ch[i]; 1446bbac5ccfSBart Van Assche if (ret) 1447d92c0da7SBart Van Assche break; 1448513d5647SBart Van Assche ret = srp_connect_ch(ch, max_iu_len, multich); 1449d92c0da7SBart Van Assche multich = true; 1450d92c0da7SBart Van Assche } 145109be70a2SBart Van Assche 1452ed9b2264SBart Van Assche if (ret == 0) 1453ed9b2264SBart Van Assche shost_printk(KERN_INFO, target->scsi_host, 1454ed9b2264SBart Van Assche PFX "reconnect succeeded\n"); 1455aef9ec39SRoland Dreier 1456aef9ec39SRoland Dreier return ret; 1457aef9ec39SRoland Dreier } 1458aef9ec39SRoland Dreier 14598f26c9ffSDavid Dillow static void srp_map_desc(struct srp_map_state *state, dma_addr_t dma_addr, 14608f26c9ffSDavid Dillow unsigned int dma_len, u32 rkey) 1461f5358a17SRoland Dreier { 14628f26c9ffSDavid Dillow struct srp_direct_buf *desc = state->desc; 14638f26c9ffSDavid Dillow 14643ae95da8SBart Van Assche WARN_ON_ONCE(!dma_len); 14653ae95da8SBart Van Assche 14668f26c9ffSDavid Dillow desc->va = cpu_to_be64(dma_addr); 14678f26c9ffSDavid Dillow desc->key = cpu_to_be32(rkey); 14688f26c9ffSDavid Dillow desc->len = cpu_to_be32(dma_len); 14698f26c9ffSDavid Dillow 14708f26c9ffSDavid Dillow state->total_len += dma_len; 14718f26c9ffSDavid Dillow state->desc++; 14728f26c9ffSDavid Dillow state->ndesc++; 14738f26c9ffSDavid Dillow } 14748f26c9ffSDavid Dillow 14758f26c9ffSDavid Dillow static int srp_map_finish_fmr(struct srp_map_state *state, 1476509c07bcSBart Van Assche struct srp_rdma_ch *ch) 14778f26c9ffSDavid Dillow { 1478186fbc66SBart Van Assche struct srp_target_port *target = ch->target; 1479186fbc66SBart Van Assche struct srp_device *dev = target->srp_host->srp_dev; 14808f26c9ffSDavid Dillow struct ib_pool_fmr *fmr; 1481f5358a17SRoland Dreier u64 io_addr = 0; 14828f26c9ffSDavid Dillow 1483290081b4SBart Van Assche if (state->fmr.next >= state->fmr.end) { 1484290081b4SBart Van Assche shost_printk(KERN_ERR, ch->target->scsi_host, 1485290081b4SBart Van Assche PFX "Out of MRs (mr_per_cmd = %d)\n", 1486290081b4SBart Van Assche ch->target->mr_per_cmd); 1487f731ed62SBart Van Assche return -ENOMEM; 1488290081b4SBart Van Assche } 1489f731ed62SBart Van Assche 149026630e8aSSagi Grimberg WARN_ON_ONCE(!dev->use_fmr); 149126630e8aSSagi Grimberg 149226630e8aSSagi Grimberg if (state->npages == 0) 149326630e8aSSagi Grimberg return 0; 149426630e8aSSagi Grimberg 1495cee687b6SBart Van Assche if (state->npages == 1 && target->global_rkey) { 149626630e8aSSagi Grimberg srp_map_desc(state, state->base_dma_addr, state->dma_len, 1497cee687b6SBart Van Assche target->global_rkey); 149826630e8aSSagi Grimberg goto reset_state; 149926630e8aSSagi Grimberg } 150026630e8aSSagi Grimberg 1501509c07bcSBart Van Assche fmr = ib_fmr_pool_map_phys(ch->fmr_pool, state->pages, 15028f26c9ffSDavid Dillow state->npages, io_addr); 15038f26c9ffSDavid Dillow if (IS_ERR(fmr)) 15048f26c9ffSDavid Dillow return PTR_ERR(fmr); 15058f26c9ffSDavid Dillow 1506f731ed62SBart Van Assche *state->fmr.next++ = fmr; 150752ede08fSBart Van Assche state->nmdesc++; 15088f26c9ffSDavid Dillow 1509186fbc66SBart Van Assche srp_map_desc(state, state->base_dma_addr & ~dev->mr_page_mask, 1510186fbc66SBart Van Assche state->dma_len, fmr->fmr->rkey); 1511539dde6fSBart Van Assche 151226630e8aSSagi Grimberg reset_state: 151326630e8aSSagi Grimberg state->npages = 0; 151426630e8aSSagi Grimberg state->dma_len = 0; 151526630e8aSSagi Grimberg 15168f26c9ffSDavid Dillow return 0; 15178f26c9ffSDavid Dillow } 15188f26c9ffSDavid Dillow 15191dc7b1f1SChristoph Hellwig static void srp_reg_mr_err_done(struct ib_cq *cq, struct ib_wc *wc) 15201dc7b1f1SChristoph Hellwig { 15211dc7b1f1SChristoph Hellwig srp_handle_qp_err(cq, wc, "FAST REG"); 15221dc7b1f1SChristoph Hellwig } 15231dc7b1f1SChristoph Hellwig 1524509c5f33SBart Van Assche /* 1525509c5f33SBart Van Assche * Map up to sg_nents elements of state->sg where *sg_offset_p is the offset 1526509c5f33SBart Van Assche * where to start in the first element. If sg_offset_p != NULL then 1527509c5f33SBart Van Assche * *sg_offset_p is updated to the offset in state->sg[retval] of the first 1528509c5f33SBart Van Assche * byte that has not yet been mapped. 1529509c5f33SBart Van Assche */ 15305cfb1782SBart Van Assche static int srp_map_finish_fr(struct srp_map_state *state, 15311dc7b1f1SChristoph Hellwig struct srp_request *req, 1532509c5f33SBart Van Assche struct srp_rdma_ch *ch, int sg_nents, 1533509c5f33SBart Van Assche unsigned int *sg_offset_p) 15345cfb1782SBart Van Assche { 1535509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 15365cfb1782SBart Van Assche struct srp_device *dev = target->srp_host->srp_dev; 1537f7f7aab1SSagi Grimberg struct ib_reg_wr wr; 15385cfb1782SBart Van Assche struct srp_fr_desc *desc; 15395cfb1782SBart Van Assche u32 rkey; 1540f7f7aab1SSagi Grimberg int n, err; 15415cfb1782SBart Van Assche 1542290081b4SBart Van Assche if (state->fr.next >= state->fr.end) { 1543290081b4SBart Van Assche shost_printk(KERN_ERR, ch->target->scsi_host, 1544290081b4SBart Van Assche PFX "Out of MRs (mr_per_cmd = %d)\n", 1545290081b4SBart Van Assche ch->target->mr_per_cmd); 1546f731ed62SBart Van Assche return -ENOMEM; 1547290081b4SBart Van Assche } 1548f731ed62SBart Van Assche 154926630e8aSSagi Grimberg WARN_ON_ONCE(!dev->use_fast_reg); 155026630e8aSSagi Grimberg 1551cee687b6SBart Van Assche if (sg_nents == 1 && target->global_rkey) { 1552509c5f33SBart Van Assche unsigned int sg_offset = sg_offset_p ? *sg_offset_p : 0; 1553509c5f33SBart Van Assche 1554509c5f33SBart Van Assche srp_map_desc(state, sg_dma_address(state->sg) + sg_offset, 1555509c5f33SBart Van Assche sg_dma_len(state->sg) - sg_offset, 1556cee687b6SBart Van Assche target->global_rkey); 1557509c5f33SBart Van Assche if (sg_offset_p) 1558509c5f33SBart Van Assche *sg_offset_p = 0; 1559f7f7aab1SSagi Grimberg return 1; 156026630e8aSSagi Grimberg } 156126630e8aSSagi Grimberg 1562509c07bcSBart Van Assche desc = srp_fr_pool_get(ch->fr_pool); 15635cfb1782SBart Van Assche if (!desc) 15645cfb1782SBart Van Assche return -ENOMEM; 15655cfb1782SBart Van Assche 15665cfb1782SBart Van Assche rkey = ib_inc_rkey(desc->mr->rkey); 15675cfb1782SBart Van Assche ib_update_fast_reg_key(desc->mr, rkey); 15685cfb1782SBart Van Assche 1569509c5f33SBart Van Assche n = ib_map_mr_sg(desc->mr, state->sg, sg_nents, sg_offset_p, 1570509c5f33SBart Van Assche dev->mr_page_size); 15719d8e7d0dSBart Van Assche if (unlikely(n < 0)) { 15729d8e7d0dSBart Van Assche srp_fr_pool_put(ch->fr_pool, &desc, 1); 1573509c5f33SBart Van Assche pr_debug("%s: ib_map_mr_sg(%d, %d) returned %d.\n", 15749d8e7d0dSBart Van Assche dev_name(&req->scmnd->device->sdev_gendev), sg_nents, 1575509c5f33SBart Van Assche sg_offset_p ? *sg_offset_p : -1, n); 1576f7f7aab1SSagi Grimberg return n; 15779d8e7d0dSBart Van Assche } 15785cfb1782SBart Van Assche 1579509c5f33SBart Van Assche WARN_ON_ONCE(desc->mr->length == 0); 15805cfb1782SBart Van Assche 15811dc7b1f1SChristoph Hellwig req->reg_cqe.done = srp_reg_mr_err_done; 15821dc7b1f1SChristoph Hellwig 1583f7f7aab1SSagi Grimberg wr.wr.next = NULL; 1584f7f7aab1SSagi Grimberg wr.wr.opcode = IB_WR_REG_MR; 15851dc7b1f1SChristoph Hellwig wr.wr.wr_cqe = &req->reg_cqe; 1586f7f7aab1SSagi Grimberg wr.wr.num_sge = 0; 1587f7f7aab1SSagi Grimberg wr.wr.send_flags = 0; 1588f7f7aab1SSagi Grimberg wr.mr = desc->mr; 1589f7f7aab1SSagi Grimberg wr.key = desc->mr->rkey; 1590f7f7aab1SSagi Grimberg wr.access = (IB_ACCESS_LOCAL_WRITE | 15915cfb1782SBart Van Assche IB_ACCESS_REMOTE_READ | 15925cfb1782SBart Van Assche IB_ACCESS_REMOTE_WRITE); 15935cfb1782SBart Van Assche 1594f731ed62SBart Van Assche *state->fr.next++ = desc; 15955cfb1782SBart Van Assche state->nmdesc++; 15965cfb1782SBart Van Assche 1597f7f7aab1SSagi Grimberg srp_map_desc(state, desc->mr->iova, 1598f7f7aab1SSagi Grimberg desc->mr->length, desc->mr->rkey); 15995cfb1782SBart Van Assche 160071347b0cSBart Van Assche err = ib_post_send(ch->qp, &wr.wr, NULL); 1601509c5f33SBart Van Assche if (unlikely(err)) { 1602509c5f33SBart Van Assche WARN_ON_ONCE(err == -ENOMEM); 160326630e8aSSagi Grimberg return err; 1604509c5f33SBart Van Assche } 160526630e8aSSagi Grimberg 1606f7f7aab1SSagi Grimberg return n; 16075cfb1782SBart Van Assche } 16085cfb1782SBart Van Assche 16098f26c9ffSDavid Dillow static int srp_map_sg_entry(struct srp_map_state *state, 1610509c07bcSBart Van Assche struct srp_rdma_ch *ch, 161152bb8c62SBart Van Assche struct scatterlist *sg) 16128f26c9ffSDavid Dillow { 1613509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 161405321937SGreg Kroah-Hartman struct srp_device *dev = target->srp_host->srp_dev; 1615a163afc8SBart Van Assche dma_addr_t dma_addr = sg_dma_address(sg); 1616a163afc8SBart Van Assche unsigned int dma_len = sg_dma_len(sg); 16173ae95da8SBart Van Assche unsigned int len = 0; 16188f26c9ffSDavid Dillow int ret; 161985507bccSRalph Campbell 16203ae95da8SBart Van Assche WARN_ON_ONCE(!dma_len); 1621f5358a17SRoland Dreier 16228f26c9ffSDavid Dillow while (dma_len) { 16235cfb1782SBart Van Assche unsigned offset = dma_addr & ~dev->mr_page_mask; 1624681cc360SBart Van Assche 1625681cc360SBart Van Assche if (state->npages == dev->max_pages_per_mr || 1626681cc360SBart Van Assche (state->npages > 0 && offset != 0)) { 1627f7f7aab1SSagi Grimberg ret = srp_map_finish_fmr(state, ch); 16288f26c9ffSDavid Dillow if (ret) 16298f26c9ffSDavid Dillow return ret; 163085507bccSRalph Campbell } 1631f5358a17SRoland Dreier 16325cfb1782SBart Van Assche len = min_t(unsigned int, dma_len, dev->mr_page_size - offset); 16338f26c9ffSDavid Dillow 16348f26c9ffSDavid Dillow if (!state->npages) 16358f26c9ffSDavid Dillow state->base_dma_addr = dma_addr; 16365cfb1782SBart Van Assche state->pages[state->npages++] = dma_addr & dev->mr_page_mask; 163752ede08fSBart Van Assche state->dma_len += len; 16388f26c9ffSDavid Dillow dma_addr += len; 16398f26c9ffSDavid Dillow dma_len -= len; 1640f5358a17SRoland Dreier } 1641f5358a17SRoland Dreier 16425cfb1782SBart Van Assche /* 1643681cc360SBart Van Assche * If the end of the MR is not on a page boundary then we need to 16448f26c9ffSDavid Dillow * close it out and start a new one -- we can only merge at page 16451d3d98c4SBart Van Assche * boundaries. 16468f26c9ffSDavid Dillow */ 1647f5358a17SRoland Dreier ret = 0; 1648681cc360SBart Van Assche if ((dma_addr & ~dev->mr_page_mask) != 0) 1649f7f7aab1SSagi Grimberg ret = srp_map_finish_fmr(state, ch); 1650f5358a17SRoland Dreier return ret; 1651f5358a17SRoland Dreier } 1652f5358a17SRoland Dreier 165326630e8aSSagi Grimberg static int srp_map_sg_fmr(struct srp_map_state *state, struct srp_rdma_ch *ch, 165426630e8aSSagi Grimberg struct srp_request *req, struct scatterlist *scat, 165526630e8aSSagi Grimberg int count) 165626630e8aSSagi Grimberg { 165726630e8aSSagi Grimberg struct scatterlist *sg; 165826630e8aSSagi Grimberg int i, ret; 165926630e8aSSagi Grimberg 166026630e8aSSagi Grimberg state->pages = req->map_page; 166126630e8aSSagi Grimberg state->fmr.next = req->fmr_list; 1662509c5f33SBart Van Assche state->fmr.end = req->fmr_list + ch->target->mr_per_cmd; 166326630e8aSSagi Grimberg 166426630e8aSSagi Grimberg for_each_sg(scat, sg, count, i) { 166552bb8c62SBart Van Assche ret = srp_map_sg_entry(state, ch, sg); 166626630e8aSSagi Grimberg if (ret) 166726630e8aSSagi Grimberg return ret; 166826630e8aSSagi Grimberg } 166926630e8aSSagi Grimberg 1670f7f7aab1SSagi Grimberg ret = srp_map_finish_fmr(state, ch); 167126630e8aSSagi Grimberg if (ret) 167226630e8aSSagi Grimberg return ret; 167326630e8aSSagi Grimberg 167426630e8aSSagi Grimberg return 0; 167526630e8aSSagi Grimberg } 167626630e8aSSagi Grimberg 167726630e8aSSagi Grimberg static int srp_map_sg_fr(struct srp_map_state *state, struct srp_rdma_ch *ch, 167826630e8aSSagi Grimberg struct srp_request *req, struct scatterlist *scat, 167926630e8aSSagi Grimberg int count) 168026630e8aSSagi Grimberg { 1681509c5f33SBart Van Assche unsigned int sg_offset = 0; 1682509c5f33SBart Van Assche 1683f7f7aab1SSagi Grimberg state->fr.next = req->fr_list; 1684509c5f33SBart Van Assche state->fr.end = req->fr_list + ch->target->mr_per_cmd; 1685f7f7aab1SSagi Grimberg state->sg = scat; 168626630e8aSSagi Grimberg 16873b59b7a6SBart Van Assche if (count == 0) 16883b59b7a6SBart Van Assche return 0; 16893b59b7a6SBart Van Assche 169057b0be9cSBart Van Assche while (count) { 1691f7f7aab1SSagi Grimberg int i, n; 1692f7f7aab1SSagi Grimberg 1693509c5f33SBart Van Assche n = srp_map_finish_fr(state, req, ch, count, &sg_offset); 1694f7f7aab1SSagi Grimberg if (unlikely(n < 0)) 1695f7f7aab1SSagi Grimberg return n; 1696f7f7aab1SSagi Grimberg 169757b0be9cSBart Van Assche count -= n; 1698f7f7aab1SSagi Grimberg for (i = 0; i < n; i++) 1699f7f7aab1SSagi Grimberg state->sg = sg_next(state->sg); 170026630e8aSSagi Grimberg } 170126630e8aSSagi Grimberg 170226630e8aSSagi Grimberg return 0; 170326630e8aSSagi Grimberg } 170426630e8aSSagi Grimberg 170526630e8aSSagi Grimberg static int srp_map_sg_dma(struct srp_map_state *state, struct srp_rdma_ch *ch, 1706509c07bcSBart Van Assche struct srp_request *req, struct scatterlist *scat, 1707509c07bcSBart Van Assche int count) 170876bc1e1dSBart Van Assche { 1709509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 171076bc1e1dSBart Van Assche struct scatterlist *sg; 171126630e8aSSagi Grimberg int i; 171276bc1e1dSBart Van Assche 17133ae95da8SBart Van Assche for_each_sg(scat, sg, count, i) { 1714a163afc8SBart Van Assche srp_map_desc(state, sg_dma_address(sg), sg_dma_len(sg), 1715cee687b6SBart Van Assche target->global_rkey); 17163ae95da8SBart Van Assche } 171776bc1e1dSBart Van Assche 171826630e8aSSagi Grimberg return 0; 171976bc1e1dSBart Van Assche } 172076bc1e1dSBart Van Assche 1721330179f2SBart Van Assche /* 1722330179f2SBart Van Assche * Register the indirect data buffer descriptor with the HCA. 1723330179f2SBart Van Assche * 1724330179f2SBart Van Assche * Note: since the indirect data buffer descriptor has been allocated with 1725330179f2SBart Van Assche * kmalloc() it is guaranteed that this buffer is a physically contiguous 1726330179f2SBart Van Assche * memory buffer. 1727330179f2SBart Van Assche */ 1728330179f2SBart Van Assche static int srp_map_idb(struct srp_rdma_ch *ch, struct srp_request *req, 1729330179f2SBart Van Assche void **next_mr, void **end_mr, u32 idb_len, 1730330179f2SBart Van Assche __be32 *idb_rkey) 1731330179f2SBart Van Assche { 1732330179f2SBart Van Assche struct srp_target_port *target = ch->target; 1733330179f2SBart Van Assche struct srp_device *dev = target->srp_host->srp_dev; 1734330179f2SBart Van Assche struct srp_map_state state; 1735330179f2SBart Van Assche struct srp_direct_buf idb_desc; 1736330179f2SBart Van Assche u64 idb_pages[1]; 1737f7f7aab1SSagi Grimberg struct scatterlist idb_sg[1]; 1738330179f2SBart Van Assche int ret; 1739330179f2SBart Van Assche 1740330179f2SBart Van Assche memset(&state, 0, sizeof(state)); 1741330179f2SBart Van Assche memset(&idb_desc, 0, sizeof(idb_desc)); 1742330179f2SBart Van Assche state.gen.next = next_mr; 1743330179f2SBart Van Assche state.gen.end = end_mr; 1744330179f2SBart Van Assche state.desc = &idb_desc; 1745f7f7aab1SSagi Grimberg state.base_dma_addr = req->indirect_dma_addr; 1746f7f7aab1SSagi Grimberg state.dma_len = idb_len; 1747f7f7aab1SSagi Grimberg 1748f7f7aab1SSagi Grimberg if (dev->use_fast_reg) { 1749f7f7aab1SSagi Grimberg state.sg = idb_sg; 175054f5c9c5SBart Van Assche sg_init_one(idb_sg, req->indirect_desc, idb_len); 1751f7f7aab1SSagi Grimberg idb_sg->dma_address = req->indirect_dma_addr; /* hack! */ 1752fc925518SChristoph Hellwig #ifdef CONFIG_NEED_SG_DMA_LENGTH 1753fc925518SChristoph Hellwig idb_sg->dma_length = idb_sg->length; /* hack^2 */ 1754fc925518SChristoph Hellwig #endif 1755509c5f33SBart Van Assche ret = srp_map_finish_fr(&state, req, ch, 1, NULL); 1756f7f7aab1SSagi Grimberg if (ret < 0) 1757f7f7aab1SSagi Grimberg return ret; 1758509c5f33SBart Van Assche WARN_ON_ONCE(ret < 1); 1759f7f7aab1SSagi Grimberg } else if (dev->use_fmr) { 1760330179f2SBart Van Assche state.pages = idb_pages; 1761330179f2SBart Van Assche state.pages[0] = (req->indirect_dma_addr & 1762330179f2SBart Van Assche dev->mr_page_mask); 1763330179f2SBart Van Assche state.npages = 1; 1764f7f7aab1SSagi Grimberg ret = srp_map_finish_fmr(&state, ch); 1765330179f2SBart Van Assche if (ret < 0) 1766f7f7aab1SSagi Grimberg return ret; 1767f7f7aab1SSagi Grimberg } else { 1768f7f7aab1SSagi Grimberg return -EINVAL; 1769f7f7aab1SSagi Grimberg } 1770330179f2SBart Van Assche 1771330179f2SBart Van Assche *idb_rkey = idb_desc.key; 1772330179f2SBart Van Assche 1773f7f7aab1SSagi Grimberg return 0; 1774330179f2SBart Van Assche } 1775330179f2SBart Van Assche 1776509c5f33SBart Van Assche static void srp_check_mapping(struct srp_map_state *state, 1777509c5f33SBart Van Assche struct srp_rdma_ch *ch, struct srp_request *req, 1778509c5f33SBart Van Assche struct scatterlist *scat, int count) 1779509c5f33SBart Van Assche { 1780509c5f33SBart Van Assche struct srp_device *dev = ch->target->srp_host->srp_dev; 1781509c5f33SBart Van Assche struct srp_fr_desc **pfr; 1782509c5f33SBart Van Assche u64 desc_len = 0, mr_len = 0; 1783509c5f33SBart Van Assche int i; 1784509c5f33SBart Van Assche 1785509c5f33SBart Van Assche for (i = 0; i < state->ndesc; i++) 1786509c5f33SBart Van Assche desc_len += be32_to_cpu(req->indirect_desc[i].len); 1787509c5f33SBart Van Assche if (dev->use_fast_reg) 1788509c5f33SBart Van Assche for (i = 0, pfr = req->fr_list; i < state->nmdesc; i++, pfr++) 1789509c5f33SBart Van Assche mr_len += (*pfr)->mr->length; 1790509c5f33SBart Van Assche else if (dev->use_fmr) 1791509c5f33SBart Van Assche for (i = 0; i < state->nmdesc; i++) 1792509c5f33SBart Van Assche mr_len += be32_to_cpu(req->indirect_desc[i].len); 1793509c5f33SBart Van Assche if (desc_len != scsi_bufflen(req->scmnd) || 1794509c5f33SBart Van Assche mr_len > scsi_bufflen(req->scmnd)) 1795509c5f33SBart Van Assche pr_err("Inconsistent: scsi len %d <> desc len %lld <> mr len %lld; ndesc %d; nmdesc = %d\n", 1796509c5f33SBart Van Assche scsi_bufflen(req->scmnd), desc_len, mr_len, 1797509c5f33SBart Van Assche state->ndesc, state->nmdesc); 1798509c5f33SBart Van Assche } 1799509c5f33SBart Van Assche 180077269cdfSBart Van Assche /** 180177269cdfSBart Van Assche * srp_map_data() - map SCSI data buffer onto an SRP request 180277269cdfSBart Van Assche * @scmnd: SCSI command to map 180377269cdfSBart Van Assche * @ch: SRP RDMA channel 180477269cdfSBart Van Assche * @req: SRP request 180577269cdfSBart Van Assche * 180677269cdfSBart Van Assche * Returns the length in bytes of the SRP_CMD IU or a negative value if 1807882981f4SBart Van Assche * mapping failed. The size of any immediate data is not included in the 1808882981f4SBart Van Assche * return value. 180977269cdfSBart Van Assche */ 1810509c07bcSBart Van Assche static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_rdma_ch *ch, 1811aef9ec39SRoland Dreier struct srp_request *req) 1812aef9ec39SRoland Dreier { 1813509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 1814882981f4SBart Van Assche struct scatterlist *scat, *sg; 1815aef9ec39SRoland Dreier struct srp_cmd *cmd = req->cmd->buf; 1816882981f4SBart Van Assche int i, len, nents, count, ret; 181785507bccSRalph Campbell struct srp_device *dev; 181885507bccSRalph Campbell struct ib_device *ibdev; 18198f26c9ffSDavid Dillow struct srp_map_state state; 18208f26c9ffSDavid Dillow struct srp_indirect_buf *indirect_hdr; 1821882981f4SBart Van Assche u64 data_len; 1822330179f2SBart Van Assche u32 idb_len, table_len; 1823330179f2SBart Van Assche __be32 idb_rkey; 18248f26c9ffSDavid Dillow u8 fmt; 1825aef9ec39SRoland Dreier 1826882981f4SBart Van Assche req->cmd->num_sge = 1; 1827882981f4SBart Van Assche 1828bb350d1dSFUJITA Tomonori if (!scsi_sglist(scmnd) || scmnd->sc_data_direction == DMA_NONE) 1829482fffc4SBart Van Assche return sizeof(struct srp_cmd) + cmd->add_cdb_len; 1830aef9ec39SRoland Dreier 1831aef9ec39SRoland Dreier if (scmnd->sc_data_direction != DMA_FROM_DEVICE && 1832aef9ec39SRoland Dreier scmnd->sc_data_direction != DMA_TO_DEVICE) { 18337aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 18347aa54bd7SDavid Dillow PFX "Unhandled data direction %d\n", 1835aef9ec39SRoland Dreier scmnd->sc_data_direction); 1836aef9ec39SRoland Dreier return -EINVAL; 1837aef9ec39SRoland Dreier } 1838aef9ec39SRoland Dreier 1839bb350d1dSFUJITA Tomonori nents = scsi_sg_count(scmnd); 1840bb350d1dSFUJITA Tomonori scat = scsi_sglist(scmnd); 1841882981f4SBart Van Assche data_len = scsi_bufflen(scmnd); 1842aef9ec39SRoland Dreier 184305321937SGreg Kroah-Hartman dev = target->srp_host->srp_dev; 184485507bccSRalph Campbell ibdev = dev->dev; 184585507bccSRalph Campbell 184685507bccSRalph Campbell count = ib_dma_map_sg(ibdev, scat, nents, scmnd->sc_data_direction); 18478f26c9ffSDavid Dillow if (unlikely(count == 0)) 18488f26c9ffSDavid Dillow return -EIO; 1849aef9ec39SRoland Dreier 1850882981f4SBart Van Assche if (ch->use_imm_data && 1851bf583470SBart Van Assche count <= ch->max_imm_sge && 1852882981f4SBart Van Assche SRP_IMM_DATA_OFFSET + data_len <= ch->max_it_iu_len && 1853882981f4SBart Van Assche scmnd->sc_data_direction == DMA_TO_DEVICE) { 1854882981f4SBart Van Assche struct srp_imm_buf *buf; 1855882981f4SBart Van Assche struct ib_sge *sge = &req->cmd->sge[1]; 1856882981f4SBart Van Assche 1857882981f4SBart Van Assche fmt = SRP_DATA_DESC_IMM; 1858882981f4SBart Van Assche len = SRP_IMM_DATA_OFFSET; 1859882981f4SBart Van Assche req->nmdesc = 0; 1860882981f4SBart Van Assche buf = (void *)cmd->add_data + cmd->add_cdb_len; 1861882981f4SBart Van Assche buf->len = cpu_to_be32(data_len); 1862882981f4SBart Van Assche WARN_ON_ONCE((void *)(buf + 1) > (void *)cmd + len); 1863882981f4SBart Van Assche for_each_sg(scat, sg, count, i) { 1864a163afc8SBart Van Assche sge[i].addr = sg_dma_address(sg); 1865a163afc8SBart Van Assche sge[i].length = sg_dma_len(sg); 1866882981f4SBart Van Assche sge[i].lkey = target->lkey; 1867882981f4SBart Van Assche } 1868882981f4SBart Van Assche req->cmd->num_sge += count; 1869882981f4SBart Van Assche goto map_complete; 1870882981f4SBart Van Assche } 1871882981f4SBart Van Assche 1872aef9ec39SRoland Dreier fmt = SRP_DATA_DESC_DIRECT; 1873482fffc4SBart Van Assche len = sizeof(struct srp_cmd) + cmd->add_cdb_len + 1874482fffc4SBart Van Assche sizeof(struct srp_direct_buf); 1875f5358a17SRoland Dreier 1876cee687b6SBart Van Assche if (count == 1 && target->global_rkey) { 1877f5358a17SRoland Dreier /* 1878f5358a17SRoland Dreier * The midlayer only generated a single gather/scatter 1879f5358a17SRoland Dreier * entry, or DMA mapping coalesced everything to a 1880f5358a17SRoland Dreier * single entry. So a direct descriptor along with 1881f5358a17SRoland Dreier * the DMA MR suffices. 1882f5358a17SRoland Dreier */ 1883482fffc4SBart Van Assche struct srp_direct_buf *buf; 1884aef9ec39SRoland Dreier 1885482fffc4SBart Van Assche buf = (void *)cmd->add_data + cmd->add_cdb_len; 1886a163afc8SBart Van Assche buf->va = cpu_to_be64(sg_dma_address(scat)); 1887cee687b6SBart Van Assche buf->key = cpu_to_be32(target->global_rkey); 1888a163afc8SBart Van Assche buf->len = cpu_to_be32(sg_dma_len(scat)); 18898f26c9ffSDavid Dillow 189052ede08fSBart Van Assche req->nmdesc = 0; 18918f26c9ffSDavid Dillow goto map_complete; 18928f26c9ffSDavid Dillow } 18938f26c9ffSDavid Dillow 18945cfb1782SBart Van Assche /* 18955cfb1782SBart Van Assche * We have more than one scatter/gather entry, so build our indirect 18965cfb1782SBart Van Assche * descriptor table, trying to merge as many entries as we can. 1897f5358a17SRoland Dreier */ 1898482fffc4SBart Van Assche indirect_hdr = (void *)cmd->add_data + cmd->add_cdb_len; 18998f26c9ffSDavid Dillow 1900c07d424dSDavid Dillow ib_dma_sync_single_for_cpu(ibdev, req->indirect_dma_addr, 1901c07d424dSDavid Dillow target->indirect_size, DMA_TO_DEVICE); 1902c07d424dSDavid Dillow 19038f26c9ffSDavid Dillow memset(&state, 0, sizeof(state)); 19049edba790SBart Van Assche state.desc = req->indirect_desc; 190526630e8aSSagi Grimberg if (dev->use_fast_reg) 1906e012f363SBart Van Assche ret = srp_map_sg_fr(&state, ch, req, scat, count); 190726630e8aSSagi Grimberg else if (dev->use_fmr) 1908e012f363SBart Van Assche ret = srp_map_sg_fmr(&state, ch, req, scat, count); 190926630e8aSSagi Grimberg else 1910e012f363SBart Van Assche ret = srp_map_sg_dma(&state, ch, req, scat, count); 1911e012f363SBart Van Assche req->nmdesc = state.nmdesc; 1912e012f363SBart Van Assche if (ret < 0) 1913e012f363SBart Van Assche goto unmap; 19148f26c9ffSDavid Dillow 1915509c5f33SBart Van Assche { 1916509c5f33SBart Van Assche DEFINE_DYNAMIC_DEBUG_METADATA(ddm, 1917509c5f33SBart Van Assche "Memory mapping consistency check"); 19181a1faf7aSBart Van Assche if (DYNAMIC_DEBUG_BRANCH(ddm)) 1919509c5f33SBart Van Assche srp_check_mapping(&state, ch, req, scat, count); 1920509c5f33SBart Van Assche } 19218f26c9ffSDavid Dillow 1922c07d424dSDavid Dillow /* We've mapped the request, now pull as much of the indirect 1923c07d424dSDavid Dillow * descriptor table as we can into the command buffer. If this 1924c07d424dSDavid Dillow * target is not using an external indirect table, we are 1925c07d424dSDavid Dillow * guaranteed to fit into the command, as the SCSI layer won't 1926c07d424dSDavid Dillow * give us more S/G entries than we allow. 19278f26c9ffSDavid Dillow */ 19288f26c9ffSDavid Dillow if (state.ndesc == 1) { 19295cfb1782SBart Van Assche /* 19305cfb1782SBart Van Assche * Memory registration collapsed the sg-list into one entry, 19318f26c9ffSDavid Dillow * so use a direct descriptor. 19328f26c9ffSDavid Dillow */ 1933482fffc4SBart Van Assche struct srp_direct_buf *buf; 19348f26c9ffSDavid Dillow 1935482fffc4SBart Van Assche buf = (void *)cmd->add_data + cmd->add_cdb_len; 1936c07d424dSDavid Dillow *buf = req->indirect_desc[0]; 19378f26c9ffSDavid Dillow goto map_complete; 19388f26c9ffSDavid Dillow } 19398f26c9ffSDavid Dillow 1940c07d424dSDavid Dillow if (unlikely(target->cmd_sg_cnt < state.ndesc && 1941c07d424dSDavid Dillow !target->allow_ext_sg)) { 1942c07d424dSDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 1943c07d424dSDavid Dillow "Could not fit S/G list into SRP_CMD\n"); 1944e012f363SBart Van Assche ret = -EIO; 1945e012f363SBart Van Assche goto unmap; 1946c07d424dSDavid Dillow } 1947c07d424dSDavid Dillow 1948c07d424dSDavid Dillow count = min(state.ndesc, target->cmd_sg_cnt); 19498f26c9ffSDavid Dillow table_len = state.ndesc * sizeof (struct srp_direct_buf); 1950330179f2SBart Van Assche idb_len = sizeof(struct srp_indirect_buf) + table_len; 1951aef9ec39SRoland Dreier 1952aef9ec39SRoland Dreier fmt = SRP_DATA_DESC_INDIRECT; 1953482fffc4SBart Van Assche len = sizeof(struct srp_cmd) + cmd->add_cdb_len + 1954482fffc4SBart Van Assche sizeof(struct srp_indirect_buf); 1955c07d424dSDavid Dillow len += count * sizeof (struct srp_direct_buf); 1956f5358a17SRoland Dreier 1957c07d424dSDavid Dillow memcpy(indirect_hdr->desc_list, req->indirect_desc, 1958c07d424dSDavid Dillow count * sizeof (struct srp_direct_buf)); 195985507bccSRalph Campbell 1960cee687b6SBart Van Assche if (!target->global_rkey) { 1961330179f2SBart Van Assche ret = srp_map_idb(ch, req, state.gen.next, state.gen.end, 1962330179f2SBart Van Assche idb_len, &idb_rkey); 1963330179f2SBart Van Assche if (ret < 0) 1964e012f363SBart Van Assche goto unmap; 1965330179f2SBart Van Assche req->nmdesc++; 1966330179f2SBart Van Assche } else { 1967cee687b6SBart Van Assche idb_rkey = cpu_to_be32(target->global_rkey); 1968330179f2SBart Van Assche } 1969330179f2SBart Van Assche 1970c07d424dSDavid Dillow indirect_hdr->table_desc.va = cpu_to_be64(req->indirect_dma_addr); 1971330179f2SBart Van Assche indirect_hdr->table_desc.key = idb_rkey; 19728f26c9ffSDavid Dillow indirect_hdr->table_desc.len = cpu_to_be32(table_len); 19738f26c9ffSDavid Dillow indirect_hdr->len = cpu_to_be32(state.total_len); 1974aef9ec39SRoland Dreier 1975aef9ec39SRoland Dreier if (scmnd->sc_data_direction == DMA_TO_DEVICE) 1976c07d424dSDavid Dillow cmd->data_out_desc_cnt = count; 1977aef9ec39SRoland Dreier else 1978c07d424dSDavid Dillow cmd->data_in_desc_cnt = count; 1979c07d424dSDavid Dillow 1980c07d424dSDavid Dillow ib_dma_sync_single_for_device(ibdev, req->indirect_dma_addr, table_len, 1981c07d424dSDavid Dillow DMA_TO_DEVICE); 1982aef9ec39SRoland Dreier 19838f26c9ffSDavid Dillow map_complete: 1984aef9ec39SRoland Dreier if (scmnd->sc_data_direction == DMA_TO_DEVICE) 1985aef9ec39SRoland Dreier cmd->buf_fmt = fmt << 4; 1986aef9ec39SRoland Dreier else 1987aef9ec39SRoland Dreier cmd->buf_fmt = fmt; 1988aef9ec39SRoland Dreier 1989aef9ec39SRoland Dreier return len; 1990e012f363SBart Van Assche 1991e012f363SBart Van Assche unmap: 1992e012f363SBart Van Assche srp_unmap_data(scmnd, ch, req); 1993ffc548bbSBart Van Assche if (ret == -ENOMEM && req->nmdesc >= target->mr_pool_size) 1994ffc548bbSBart Van Assche ret = -E2BIG; 1995e012f363SBart Van Assche return ret; 1996aef9ec39SRoland Dreier } 1997aef9ec39SRoland Dreier 199805a1d750SDavid Dillow /* 199976c75b25SBart Van Assche * Return an IU and possible credit to the free pool 200076c75b25SBart Van Assche */ 2001509c07bcSBart Van Assche static void srp_put_tx_iu(struct srp_rdma_ch *ch, struct srp_iu *iu, 200276c75b25SBart Van Assche enum srp_iu_type iu_type) 200376c75b25SBart Van Assche { 200476c75b25SBart Van Assche unsigned long flags; 200576c75b25SBart Van Assche 2006509c07bcSBart Van Assche spin_lock_irqsave(&ch->lock, flags); 2007509c07bcSBart Van Assche list_add(&iu->list, &ch->free_tx); 200876c75b25SBart Van Assche if (iu_type != SRP_IU_RSP) 2009509c07bcSBart Van Assche ++ch->req_lim; 2010509c07bcSBart Van Assche spin_unlock_irqrestore(&ch->lock, flags); 201176c75b25SBart Van Assche } 201276c75b25SBart Van Assche 201376c75b25SBart Van Assche /* 2014509c07bcSBart Van Assche * Must be called with ch->lock held to protect req_lim and free_tx. 2015e9684678SBart Van Assche * If IU is not sent, it must be returned using srp_put_tx_iu(). 201605a1d750SDavid Dillow * 201705a1d750SDavid Dillow * Note: 201805a1d750SDavid Dillow * An upper limit for the number of allocated information units for each 201905a1d750SDavid Dillow * request type is: 202005a1d750SDavid Dillow * - SRP_IU_CMD: SRP_CMD_SQ_SIZE, since the SCSI mid-layer never queues 202105a1d750SDavid Dillow * more than Scsi_Host.can_queue requests. 202205a1d750SDavid Dillow * - SRP_IU_TSK_MGMT: SRP_TSK_MGMT_SQ_SIZE. 202305a1d750SDavid Dillow * - SRP_IU_RSP: 1, since a conforming SRP target never sends more than 202405a1d750SDavid Dillow * one unanswered SRP request to an initiator. 202505a1d750SDavid Dillow */ 2026509c07bcSBart Van Assche static struct srp_iu *__srp_get_tx_iu(struct srp_rdma_ch *ch, 202705a1d750SDavid Dillow enum srp_iu_type iu_type) 202805a1d750SDavid Dillow { 2029509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 203005a1d750SDavid Dillow s32 rsv = (iu_type == SRP_IU_TSK_MGMT) ? 0 : SRP_TSK_MGMT_SQ_SIZE; 203105a1d750SDavid Dillow struct srp_iu *iu; 203205a1d750SDavid Dillow 203393c76dbbSBart Van Assche lockdep_assert_held(&ch->lock); 203493c76dbbSBart Van Assche 20351dc7b1f1SChristoph Hellwig ib_process_cq_direct(ch->send_cq, -1); 203605a1d750SDavid Dillow 2037509c07bcSBart Van Assche if (list_empty(&ch->free_tx)) 203805a1d750SDavid Dillow return NULL; 203905a1d750SDavid Dillow 204005a1d750SDavid Dillow /* Initiator responses to target requests do not consume credits */ 204176c75b25SBart Van Assche if (iu_type != SRP_IU_RSP) { 2042509c07bcSBart Van Assche if (ch->req_lim <= rsv) { 204305a1d750SDavid Dillow ++target->zero_req_lim; 204405a1d750SDavid Dillow return NULL; 204505a1d750SDavid Dillow } 204605a1d750SDavid Dillow 2047509c07bcSBart Van Assche --ch->req_lim; 204876c75b25SBart Van Assche } 204976c75b25SBart Van Assche 2050509c07bcSBart Van Assche iu = list_first_entry(&ch->free_tx, struct srp_iu, list); 205176c75b25SBart Van Assche list_del(&iu->list); 205205a1d750SDavid Dillow return iu; 205305a1d750SDavid Dillow } 205405a1d750SDavid Dillow 20559294000dSBart Van Assche /* 20569294000dSBart Van Assche * Note: if this function is called from inside ib_drain_sq() then it will 20579294000dSBart Van Assche * be called without ch->lock being held. If ib_drain_sq() dequeues a WQE 20589294000dSBart Van Assche * with status IB_WC_SUCCESS then that's a bug. 20599294000dSBart Van Assche */ 20601dc7b1f1SChristoph Hellwig static void srp_send_done(struct ib_cq *cq, struct ib_wc *wc) 20611dc7b1f1SChristoph Hellwig { 20621dc7b1f1SChristoph Hellwig struct srp_iu *iu = container_of(wc->wr_cqe, struct srp_iu, cqe); 20631dc7b1f1SChristoph Hellwig struct srp_rdma_ch *ch = cq->cq_context; 20641dc7b1f1SChristoph Hellwig 20651dc7b1f1SChristoph Hellwig if (unlikely(wc->status != IB_WC_SUCCESS)) { 20661dc7b1f1SChristoph Hellwig srp_handle_qp_err(cq, wc, "SEND"); 20671dc7b1f1SChristoph Hellwig return; 20681dc7b1f1SChristoph Hellwig } 20691dc7b1f1SChristoph Hellwig 207093c76dbbSBart Van Assche lockdep_assert_held(&ch->lock); 207193c76dbbSBart Van Assche 20721dc7b1f1SChristoph Hellwig list_add(&iu->list, &ch->free_tx); 20731dc7b1f1SChristoph Hellwig } 20741dc7b1f1SChristoph Hellwig 2075882981f4SBart Van Assche /** 2076882981f4SBart Van Assche * srp_post_send() - send an SRP information unit 2077882981f4SBart Van Assche * @ch: RDMA channel over which to send the information unit. 2078882981f4SBart Van Assche * @iu: Information unit to send. 2079882981f4SBart Van Assche * @len: Length of the information unit excluding immediate data. 2080882981f4SBart Van Assche */ 2081509c07bcSBart Van Assche static int srp_post_send(struct srp_rdma_ch *ch, struct srp_iu *iu, int len) 208205a1d750SDavid Dillow { 2083509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 208471347b0cSBart Van Assche struct ib_send_wr wr; 208505a1d750SDavid Dillow 2086882981f4SBart Van Assche if (WARN_ON_ONCE(iu->num_sge > SRP_MAX_SGE)) 2087882981f4SBart Van Assche return -EINVAL; 2088882981f4SBart Van Assche 2089882981f4SBart Van Assche iu->sge[0].addr = iu->dma; 2090882981f4SBart Van Assche iu->sge[0].length = len; 2091882981f4SBart Van Assche iu->sge[0].lkey = target->lkey; 209205a1d750SDavid Dillow 20931dc7b1f1SChristoph Hellwig iu->cqe.done = srp_send_done; 20941dc7b1f1SChristoph Hellwig 209505a1d750SDavid Dillow wr.next = NULL; 20961dc7b1f1SChristoph Hellwig wr.wr_cqe = &iu->cqe; 2097882981f4SBart Van Assche wr.sg_list = &iu->sge[0]; 2098882981f4SBart Van Assche wr.num_sge = iu->num_sge; 209905a1d750SDavid Dillow wr.opcode = IB_WR_SEND; 210005a1d750SDavid Dillow wr.send_flags = IB_SEND_SIGNALED; 210105a1d750SDavid Dillow 210271347b0cSBart Van Assche return ib_post_send(ch->qp, &wr, NULL); 210305a1d750SDavid Dillow } 210405a1d750SDavid Dillow 2105509c07bcSBart Van Assche static int srp_post_recv(struct srp_rdma_ch *ch, struct srp_iu *iu) 2106c996bb47SBart Van Assche { 2107509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 210871347b0cSBart Van Assche struct ib_recv_wr wr; 2109dcb4cb85SBart Van Assche struct ib_sge list; 2110c996bb47SBart Van Assche 2111c996bb47SBart Van Assche list.addr = iu->dma; 2112c996bb47SBart Van Assche list.length = iu->size; 21139af76271SDavid Dillow list.lkey = target->lkey; 2114c996bb47SBart Van Assche 21151dc7b1f1SChristoph Hellwig iu->cqe.done = srp_recv_done; 21161dc7b1f1SChristoph Hellwig 2117c996bb47SBart Van Assche wr.next = NULL; 21181dc7b1f1SChristoph Hellwig wr.wr_cqe = &iu->cqe; 2119c996bb47SBart Van Assche wr.sg_list = &list; 2120c996bb47SBart Van Assche wr.num_sge = 1; 2121c996bb47SBart Van Assche 212271347b0cSBart Van Assche return ib_post_recv(ch->qp, &wr, NULL); 2123c996bb47SBart Van Assche } 2124c996bb47SBart Van Assche 2125509c07bcSBart Van Assche static void srp_process_rsp(struct srp_rdma_ch *ch, struct srp_rsp *rsp) 2126aef9ec39SRoland Dreier { 2127509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 2128aef9ec39SRoland Dreier struct srp_request *req; 2129aef9ec39SRoland Dreier struct scsi_cmnd *scmnd; 2130aef9ec39SRoland Dreier unsigned long flags; 2131aef9ec39SRoland Dreier 2132aef9ec39SRoland Dreier if (unlikely(rsp->tag & SRP_TAG_TSK_MGMT)) { 2133509c07bcSBart Van Assche spin_lock_irqsave(&ch->lock, flags); 2134509c07bcSBart Van Assche ch->req_lim += be32_to_cpu(rsp->req_lim_delta); 21350a6fdbdeSBart Van Assche if (rsp->tag == ch->tsk_mgmt_tag) { 2136509c07bcSBart Van Assche ch->tsk_mgmt_status = -1; 2137f8b6e31eSDavid Dillow if (be32_to_cpu(rsp->resp_data_len) >= 4) 2138509c07bcSBart Van Assche ch->tsk_mgmt_status = rsp->data[3]; 2139509c07bcSBart Van Assche complete(&ch->tsk_mgmt_done); 2140aef9ec39SRoland Dreier } else { 21410a6fdbdeSBart Van Assche shost_printk(KERN_ERR, target->scsi_host, 21420a6fdbdeSBart Van Assche "Received tsk mgmt response too late for tag %#llx\n", 21430a6fdbdeSBart Van Assche rsp->tag); 21440a6fdbdeSBart Van Assche } 21450a6fdbdeSBart Van Assche spin_unlock_irqrestore(&ch->lock, flags); 21460a6fdbdeSBart Van Assche } else { 214777f2c1a4SBart Van Assche scmnd = scsi_host_find_tag(target->scsi_host, rsp->tag); 21486cb72bc1SBart Van Assche if (scmnd && scmnd->host_scribble) { 214977f2c1a4SBart Van Assche req = (void *)scmnd->host_scribble; 215077f2c1a4SBart Van Assche scmnd = srp_claim_req(ch, req, NULL, scmnd); 21516cb72bc1SBart Van Assche } else { 21526cb72bc1SBart Van Assche scmnd = NULL; 215377f2c1a4SBart Van Assche } 215422032991SBart Van Assche if (!scmnd) { 21557aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 2156d92c0da7SBart Van Assche "Null scmnd for RSP w/tag %#016llx received on ch %td / QP %#x\n", 2157d92c0da7SBart Van Assche rsp->tag, ch - target->ch, ch->qp->qp_num); 215822032991SBart Van Assche 2159509c07bcSBart Van Assche spin_lock_irqsave(&ch->lock, flags); 2160509c07bcSBart Van Assche ch->req_lim += be32_to_cpu(rsp->req_lim_delta); 2161509c07bcSBart Van Assche spin_unlock_irqrestore(&ch->lock, flags); 216222032991SBart Van Assche 216322032991SBart Van Assche return; 216422032991SBart Van Assche } 2165aef9ec39SRoland Dreier scmnd->result = rsp->status; 2166aef9ec39SRoland Dreier 2167aef9ec39SRoland Dreier if (rsp->flags & SRP_RSP_FLAG_SNSVALID) { 2168aef9ec39SRoland Dreier memcpy(scmnd->sense_buffer, rsp->data + 2169aef9ec39SRoland Dreier be32_to_cpu(rsp->resp_data_len), 2170aef9ec39SRoland Dreier min_t(int, be32_to_cpu(rsp->sense_data_len), 2171aef9ec39SRoland Dreier SCSI_SENSE_BUFFERSIZE)); 2172aef9ec39SRoland Dreier } 2173aef9ec39SRoland Dreier 2174e714531aSBart Van Assche if (unlikely(rsp->flags & SRP_RSP_FLAG_DIUNDER)) 2175bb350d1dSFUJITA Tomonori scsi_set_resid(scmnd, be32_to_cpu(rsp->data_in_res_cnt)); 2176e714531aSBart Van Assche else if (unlikely(rsp->flags & SRP_RSP_FLAG_DIOVER)) 2177e714531aSBart Van Assche scsi_set_resid(scmnd, -be32_to_cpu(rsp->data_in_res_cnt)); 2178e714531aSBart Van Assche else if (unlikely(rsp->flags & SRP_RSP_FLAG_DOUNDER)) 2179e714531aSBart Van Assche scsi_set_resid(scmnd, be32_to_cpu(rsp->data_out_res_cnt)); 2180e714531aSBart Van Assche else if (unlikely(rsp->flags & SRP_RSP_FLAG_DOOVER)) 2181e714531aSBart Van Assche scsi_set_resid(scmnd, -be32_to_cpu(rsp->data_out_res_cnt)); 2182aef9ec39SRoland Dreier 2183509c07bcSBart Van Assche srp_free_req(ch, req, scmnd, 218422032991SBart Van Assche be32_to_cpu(rsp->req_lim_delta)); 218522032991SBart Van Assche 2186f8b6e31eSDavid Dillow scmnd->host_scribble = NULL; 2187aef9ec39SRoland Dreier scmnd->scsi_done(scmnd); 2188aef9ec39SRoland Dreier } 2189aef9ec39SRoland Dreier } 2190aef9ec39SRoland Dreier 2191509c07bcSBart Van Assche static int srp_response_common(struct srp_rdma_ch *ch, s32 req_delta, 2192bb12588aSDavid Dillow void *rsp, int len) 2193bb12588aSDavid Dillow { 2194509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 219576c75b25SBart Van Assche struct ib_device *dev = target->srp_host->srp_dev->dev; 2196bb12588aSDavid Dillow unsigned long flags; 2197bb12588aSDavid Dillow struct srp_iu *iu; 219876c75b25SBart Van Assche int err; 2199bb12588aSDavid Dillow 2200509c07bcSBart Van Assche spin_lock_irqsave(&ch->lock, flags); 2201509c07bcSBart Van Assche ch->req_lim += req_delta; 2202509c07bcSBart Van Assche iu = __srp_get_tx_iu(ch, SRP_IU_RSP); 2203509c07bcSBart Van Assche spin_unlock_irqrestore(&ch->lock, flags); 220476c75b25SBart Van Assche 2205bb12588aSDavid Dillow if (!iu) { 2206bb12588aSDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX 2207bb12588aSDavid Dillow "no IU available to send response\n"); 220876c75b25SBart Van Assche return 1; 2209bb12588aSDavid Dillow } 2210bb12588aSDavid Dillow 2211882981f4SBart Van Assche iu->num_sge = 1; 2212bb12588aSDavid Dillow ib_dma_sync_single_for_cpu(dev, iu->dma, len, DMA_TO_DEVICE); 2213bb12588aSDavid Dillow memcpy(iu->buf, rsp, len); 2214bb12588aSDavid Dillow ib_dma_sync_single_for_device(dev, iu->dma, len, DMA_TO_DEVICE); 2215bb12588aSDavid Dillow 2216509c07bcSBart Van Assche err = srp_post_send(ch, iu, len); 221776c75b25SBart Van Assche if (err) { 2218bb12588aSDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX 2219bb12588aSDavid Dillow "unable to post response: %d\n", err); 2220509c07bcSBart Van Assche srp_put_tx_iu(ch, iu, SRP_IU_RSP); 222176c75b25SBart Van Assche } 2222bb12588aSDavid Dillow 2223bb12588aSDavid Dillow return err; 2224bb12588aSDavid Dillow } 2225bb12588aSDavid Dillow 2226509c07bcSBart Van Assche static void srp_process_cred_req(struct srp_rdma_ch *ch, 2227bb12588aSDavid Dillow struct srp_cred_req *req) 2228bb12588aSDavid Dillow { 2229bb12588aSDavid Dillow struct srp_cred_rsp rsp = { 2230bb12588aSDavid Dillow .opcode = SRP_CRED_RSP, 2231bb12588aSDavid Dillow .tag = req->tag, 2232bb12588aSDavid Dillow }; 2233bb12588aSDavid Dillow s32 delta = be32_to_cpu(req->req_lim_delta); 2234bb12588aSDavid Dillow 2235509c07bcSBart Van Assche if (srp_response_common(ch, delta, &rsp, sizeof(rsp))) 2236509c07bcSBart Van Assche shost_printk(KERN_ERR, ch->target->scsi_host, PFX 2237bb12588aSDavid Dillow "problems processing SRP_CRED_REQ\n"); 2238bb12588aSDavid Dillow } 2239bb12588aSDavid Dillow 2240509c07bcSBart Van Assche static void srp_process_aer_req(struct srp_rdma_ch *ch, 2241bb12588aSDavid Dillow struct srp_aer_req *req) 2242bb12588aSDavid Dillow { 2243509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 2244bb12588aSDavid Dillow struct srp_aer_rsp rsp = { 2245bb12588aSDavid Dillow .opcode = SRP_AER_RSP, 2246bb12588aSDavid Dillow .tag = req->tag, 2247bb12588aSDavid Dillow }; 2248bb12588aSDavid Dillow s32 delta = be32_to_cpu(req->req_lim_delta); 2249bb12588aSDavid Dillow 2250bb12588aSDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX 2251985aa495SBart Van Assche "ignoring AER for LUN %llu\n", scsilun_to_int(&req->lun)); 2252bb12588aSDavid Dillow 2253509c07bcSBart Van Assche if (srp_response_common(ch, delta, &rsp, sizeof(rsp))) 2254bb12588aSDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX 2255bb12588aSDavid Dillow "problems processing SRP_AER_REQ\n"); 2256bb12588aSDavid Dillow } 2257bb12588aSDavid Dillow 22581dc7b1f1SChristoph Hellwig static void srp_recv_done(struct ib_cq *cq, struct ib_wc *wc) 2259aef9ec39SRoland Dreier { 22601dc7b1f1SChristoph Hellwig struct srp_iu *iu = container_of(wc->wr_cqe, struct srp_iu, cqe); 22611dc7b1f1SChristoph Hellwig struct srp_rdma_ch *ch = cq->cq_context; 2262509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 2263dcb4cb85SBart Van Assche struct ib_device *dev = target->srp_host->srp_dev->dev; 2264c996bb47SBart Van Assche int res; 2265aef9ec39SRoland Dreier u8 opcode; 2266aef9ec39SRoland Dreier 22671dc7b1f1SChristoph Hellwig if (unlikely(wc->status != IB_WC_SUCCESS)) { 22681dc7b1f1SChristoph Hellwig srp_handle_qp_err(cq, wc, "RECV"); 22691dc7b1f1SChristoph Hellwig return; 22701dc7b1f1SChristoph Hellwig } 22711dc7b1f1SChristoph Hellwig 2272509c07bcSBart Van Assche ib_dma_sync_single_for_cpu(dev, iu->dma, ch->max_ti_iu_len, 227385507bccSRalph Campbell DMA_FROM_DEVICE); 2274aef9ec39SRoland Dreier 2275aef9ec39SRoland Dreier opcode = *(u8 *) iu->buf; 2276aef9ec39SRoland Dreier 2277aef9ec39SRoland Dreier if (0) { 22787aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 22797aa54bd7SDavid Dillow PFX "recv completion, opcode 0x%02x\n", opcode); 22807a700811SBart Van Assche print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 8, 1, 22817a700811SBart Van Assche iu->buf, wc->byte_len, true); 2282aef9ec39SRoland Dreier } 2283aef9ec39SRoland Dreier 2284aef9ec39SRoland Dreier switch (opcode) { 2285aef9ec39SRoland Dreier case SRP_RSP: 2286509c07bcSBart Van Assche srp_process_rsp(ch, iu->buf); 2287aef9ec39SRoland Dreier break; 2288aef9ec39SRoland Dreier 2289bb12588aSDavid Dillow case SRP_CRED_REQ: 2290509c07bcSBart Van Assche srp_process_cred_req(ch, iu->buf); 2291bb12588aSDavid Dillow break; 2292bb12588aSDavid Dillow 2293bb12588aSDavid Dillow case SRP_AER_REQ: 2294509c07bcSBart Van Assche srp_process_aer_req(ch, iu->buf); 2295bb12588aSDavid Dillow break; 2296bb12588aSDavid Dillow 2297aef9ec39SRoland Dreier case SRP_T_LOGOUT: 2298aef9ec39SRoland Dreier /* XXX Handle target logout */ 22997aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 23007aa54bd7SDavid Dillow PFX "Got target logout request\n"); 2301aef9ec39SRoland Dreier break; 2302aef9ec39SRoland Dreier 2303aef9ec39SRoland Dreier default: 23047aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 23057aa54bd7SDavid Dillow PFX "Unhandled SRP opcode 0x%02x\n", opcode); 2306aef9ec39SRoland Dreier break; 2307aef9ec39SRoland Dreier } 2308aef9ec39SRoland Dreier 2309509c07bcSBart Van Assche ib_dma_sync_single_for_device(dev, iu->dma, ch->max_ti_iu_len, 231085507bccSRalph Campbell DMA_FROM_DEVICE); 2311c996bb47SBart Van Assche 2312509c07bcSBart Van Assche res = srp_post_recv(ch, iu); 2313c996bb47SBart Van Assche if (res != 0) 2314c996bb47SBart Van Assche shost_printk(KERN_ERR, target->scsi_host, 2315c996bb47SBart Van Assche PFX "Recv failed with error code %d\n", res); 2316aef9ec39SRoland Dreier } 2317aef9ec39SRoland Dreier 2318c1120f89SBart Van Assche /** 2319c1120f89SBart Van Assche * srp_tl_err_work() - handle a transport layer error 2320af24663bSBart Van Assche * @work: Work structure embedded in an SRP target port. 2321c1120f89SBart Van Assche * 2322c1120f89SBart Van Assche * Note: This function may get invoked before the rport has been created, 2323c1120f89SBart Van Assche * hence the target->rport test. 2324c1120f89SBart Van Assche */ 2325c1120f89SBart Van Assche static void srp_tl_err_work(struct work_struct *work) 2326c1120f89SBart Van Assche { 2327c1120f89SBart Van Assche struct srp_target_port *target; 2328c1120f89SBart Van Assche 2329c1120f89SBart Van Assche target = container_of(work, struct srp_target_port, tl_err_work); 2330c1120f89SBart Van Assche if (target->rport) 2331c1120f89SBart Van Assche srp_start_tl_fail_timers(target->rport); 2332c1120f89SBart Van Assche } 2333c1120f89SBart Van Assche 23341dc7b1f1SChristoph Hellwig static void srp_handle_qp_err(struct ib_cq *cq, struct ib_wc *wc, 23351dc7b1f1SChristoph Hellwig const char *opname) 2336948d1e88SBart Van Assche { 23371dc7b1f1SChristoph Hellwig struct srp_rdma_ch *ch = cq->cq_context; 23387dad6b2eSBart Van Assche struct srp_target_port *target = ch->target; 23397dad6b2eSBart Van Assche 2340c014c8cdSBart Van Assche if (ch->connected && !target->qp_in_error) { 23415cfb1782SBart Van Assche shost_printk(KERN_ERR, target->scsi_host, 23421dc7b1f1SChristoph Hellwig PFX "failed %s status %s (%d) for CQE %p\n", 23431dc7b1f1SChristoph Hellwig opname, ib_wc_status_msg(wc->status), wc->status, 23441dc7b1f1SChristoph Hellwig wc->wr_cqe); 2345c1120f89SBart Van Assche queue_work(system_long_wq, &target->tl_err_work); 23464f0af697SBart Van Assche } 2347948d1e88SBart Van Assche target->qp_in_error = true; 2348948d1e88SBart Van Assche } 2349948d1e88SBart Van Assche 235076c75b25SBart Van Assche static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd) 2351aef9ec39SRoland Dreier { 235276c75b25SBart Van Assche struct srp_target_port *target = host_to_target(shost); 2353509c07bcSBart Van Assche struct srp_rdma_ch *ch; 2354aef9ec39SRoland Dreier struct srp_request *req; 2355aef9ec39SRoland Dreier struct srp_iu *iu; 2356aef9ec39SRoland Dreier struct srp_cmd *cmd; 235785507bccSRalph Campbell struct ib_device *dev; 235876c75b25SBart Van Assche unsigned long flags; 235977f2c1a4SBart Van Assche u32 tag; 236077f2c1a4SBart Van Assche u16 idx; 2361d1b4289eSBart Van Assche int len, ret; 2362aef9ec39SRoland Dreier 2363d1b4289eSBart Van Assche scmnd->result = srp_chkready(target->rport); 2364d1b4289eSBart Van Assche if (unlikely(scmnd->result)) 2365d1b4289eSBart Van Assche goto err; 23662ce19e72SBart Van Assche 236777f2c1a4SBart Van Assche WARN_ON_ONCE(scmnd->request->tag < 0); 236877f2c1a4SBart Van Assche tag = blk_mq_unique_tag(scmnd->request); 2369d92c0da7SBart Van Assche ch = &target->ch[blk_mq_unique_tag_to_hwq(tag)]; 237077f2c1a4SBart Van Assche idx = blk_mq_unique_tag_to_tag(tag); 237177f2c1a4SBart Van Assche WARN_ONCE(idx >= target->req_ring_size, "%s: tag %#x: idx %d >= %d\n", 237277f2c1a4SBart Van Assche dev_name(&shost->shost_gendev), tag, idx, 237377f2c1a4SBart Van Assche target->req_ring_size); 2374509c07bcSBart Van Assche 2375509c07bcSBart Van Assche spin_lock_irqsave(&ch->lock, flags); 2376509c07bcSBart Van Assche iu = __srp_get_tx_iu(ch, SRP_IU_CMD); 2377509c07bcSBart Van Assche spin_unlock_irqrestore(&ch->lock, flags); 2378aef9ec39SRoland Dreier 237977f2c1a4SBart Van Assche if (!iu) 238077f2c1a4SBart Van Assche goto err; 238177f2c1a4SBart Van Assche 238277f2c1a4SBart Van Assche req = &ch->req_ring[idx]; 238305321937SGreg Kroah-Hartman dev = target->srp_host->srp_dev->dev; 2384513d5647SBart Van Assche ib_dma_sync_single_for_cpu(dev, iu->dma, ch->max_it_iu_len, 238585507bccSRalph Campbell DMA_TO_DEVICE); 2386aef9ec39SRoland Dreier 2387f8b6e31eSDavid Dillow scmnd->host_scribble = (void *) req; 2388aef9ec39SRoland Dreier 2389aef9ec39SRoland Dreier cmd = iu->buf; 2390aef9ec39SRoland Dreier memset(cmd, 0, sizeof *cmd); 2391aef9ec39SRoland Dreier 2392aef9ec39SRoland Dreier cmd->opcode = SRP_CMD; 2393985aa495SBart Van Assche int_to_scsilun(scmnd->device->lun, &cmd->lun); 239477f2c1a4SBart Van Assche cmd->tag = tag; 2395aef9ec39SRoland Dreier memcpy(cmd->cdb, scmnd->cmnd, scmnd->cmd_len); 2396482fffc4SBart Van Assche if (unlikely(scmnd->cmd_len > sizeof(cmd->cdb))) { 2397482fffc4SBart Van Assche cmd->add_cdb_len = round_up(scmnd->cmd_len - sizeof(cmd->cdb), 2398482fffc4SBart Van Assche 4); 2399482fffc4SBart Van Assche if (WARN_ON_ONCE(cmd->add_cdb_len > SRP_MAX_ADD_CDB_LEN)) 2400482fffc4SBart Van Assche goto err_iu; 2401482fffc4SBart Van Assche } 2402aef9ec39SRoland Dreier 2403aef9ec39SRoland Dreier req->scmnd = scmnd; 2404aef9ec39SRoland Dreier req->cmd = iu; 2405aef9ec39SRoland Dreier 2406509c07bcSBart Van Assche len = srp_map_data(scmnd, ch, req); 2407aef9ec39SRoland Dreier if (len < 0) { 24087aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 2409d1b4289eSBart Van Assche PFX "Failed to map data (%d)\n", len); 2410d1b4289eSBart Van Assche /* 2411d1b4289eSBart Van Assche * If we ran out of memory descriptors (-ENOMEM) because an 2412d1b4289eSBart Van Assche * application is queuing many requests with more than 241352ede08fSBart Van Assche * max_pages_per_mr sg-list elements, tell the SCSI mid-layer 2414d1b4289eSBart Van Assche * to reduce queue depth temporarily. 2415d1b4289eSBart Van Assche */ 2416d1b4289eSBart Van Assche scmnd->result = len == -ENOMEM ? 2417d1b4289eSBart Van Assche DID_OK << 16 | QUEUE_FULL << 1 : DID_ERROR << 16; 241876c75b25SBart Van Assche goto err_iu; 2419aef9ec39SRoland Dreier } 2420aef9ec39SRoland Dreier 2421513d5647SBart Van Assche ib_dma_sync_single_for_device(dev, iu->dma, ch->max_it_iu_len, 242285507bccSRalph Campbell DMA_TO_DEVICE); 2423aef9ec39SRoland Dreier 2424509c07bcSBart Van Assche if (srp_post_send(ch, iu, len)) { 24257aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX "Send failed\n"); 24262ee00f6aSBart Van Assche scmnd->result = DID_ERROR << 16; 2427aef9ec39SRoland Dreier goto err_unmap; 2428aef9ec39SRoland Dreier } 2429aef9ec39SRoland Dreier 2430fd561412SBart Van Assche return 0; 2431aef9ec39SRoland Dreier 2432aef9ec39SRoland Dreier err_unmap: 2433509c07bcSBart Van Assche srp_unmap_data(scmnd, ch, req); 2434aef9ec39SRoland Dreier 243576c75b25SBart Van Assche err_iu: 2436509c07bcSBart Van Assche srp_put_tx_iu(ch, iu, SRP_IU_CMD); 243776c75b25SBart Van Assche 2438024ca901SBart Van Assche /* 2439024ca901SBart Van Assche * Avoid that the loops that iterate over the request ring can 2440024ca901SBart Van Assche * encounter a dangling SCSI command pointer. 2441024ca901SBart Van Assche */ 2442024ca901SBart Van Assche req->scmnd = NULL; 2443024ca901SBart Van Assche 2444d1b4289eSBart Van Assche err: 2445d1b4289eSBart Van Assche if (scmnd->result) { 2446d1b4289eSBart Van Assche scmnd->scsi_done(scmnd); 2447d1b4289eSBart Van Assche ret = 0; 2448d1b4289eSBart Van Assche } else { 2449d1b4289eSBart Van Assche ret = SCSI_MLQUEUE_HOST_BUSY; 2450d1b4289eSBart Van Assche } 2451a95cadb9SBart Van Assche 2452fd561412SBart Van Assche return ret; 2453aef9ec39SRoland Dreier } 2454aef9ec39SRoland Dreier 24554d73f95fSBart Van Assche /* 24564d73f95fSBart Van Assche * Note: the resources allocated in this function are freed in 2457509c07bcSBart Van Assche * srp_free_ch_ib(). 24584d73f95fSBart Van Assche */ 2459509c07bcSBart Van Assche static int srp_alloc_iu_bufs(struct srp_rdma_ch *ch) 2460aef9ec39SRoland Dreier { 2461509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 2462aef9ec39SRoland Dreier int i; 2463aef9ec39SRoland Dreier 2464509c07bcSBart Van Assche ch->rx_ring = kcalloc(target->queue_size, sizeof(*ch->rx_ring), 24654d73f95fSBart Van Assche GFP_KERNEL); 2466509c07bcSBart Van Assche if (!ch->rx_ring) 24674d73f95fSBart Van Assche goto err_no_ring; 2468509c07bcSBart Van Assche ch->tx_ring = kcalloc(target->queue_size, sizeof(*ch->tx_ring), 24694d73f95fSBart Van Assche GFP_KERNEL); 2470509c07bcSBart Van Assche if (!ch->tx_ring) 24714d73f95fSBart Van Assche goto err_no_ring; 24724d73f95fSBart Van Assche 24734d73f95fSBart Van Assche for (i = 0; i < target->queue_size; ++i) { 2474509c07bcSBart Van Assche ch->rx_ring[i] = srp_alloc_iu(target->srp_host, 2475509c07bcSBart Van Assche ch->max_ti_iu_len, 2476aef9ec39SRoland Dreier GFP_KERNEL, DMA_FROM_DEVICE); 2477509c07bcSBart Van Assche if (!ch->rx_ring[i]) 2478aef9ec39SRoland Dreier goto err; 2479aef9ec39SRoland Dreier } 2480aef9ec39SRoland Dreier 24814d73f95fSBart Van Assche for (i = 0; i < target->queue_size; ++i) { 2482509c07bcSBart Van Assche ch->tx_ring[i] = srp_alloc_iu(target->srp_host, 2483513d5647SBart Van Assche ch->max_it_iu_len, 2484aef9ec39SRoland Dreier GFP_KERNEL, DMA_TO_DEVICE); 2485509c07bcSBart Van Assche if (!ch->tx_ring[i]) 2486aef9ec39SRoland Dreier goto err; 2487dcb4cb85SBart Van Assche 2488509c07bcSBart Van Assche list_add(&ch->tx_ring[i]->list, &ch->free_tx); 2489aef9ec39SRoland Dreier } 2490aef9ec39SRoland Dreier 2491aef9ec39SRoland Dreier return 0; 2492aef9ec39SRoland Dreier 2493aef9ec39SRoland Dreier err: 24944d73f95fSBart Van Assche for (i = 0; i < target->queue_size; ++i) { 2495509c07bcSBart Van Assche srp_free_iu(target->srp_host, ch->rx_ring[i]); 2496509c07bcSBart Van Assche srp_free_iu(target->srp_host, ch->tx_ring[i]); 2497aef9ec39SRoland Dreier } 2498aef9ec39SRoland Dreier 24994d73f95fSBart Van Assche 25004d73f95fSBart Van Assche err_no_ring: 2501509c07bcSBart Van Assche kfree(ch->tx_ring); 2502509c07bcSBart Van Assche ch->tx_ring = NULL; 2503509c07bcSBart Van Assche kfree(ch->rx_ring); 2504509c07bcSBart Van Assche ch->rx_ring = NULL; 2505aef9ec39SRoland Dreier 2506aef9ec39SRoland Dreier return -ENOMEM; 2507aef9ec39SRoland Dreier } 2508aef9ec39SRoland Dreier 2509c9b03c1aSBart Van Assche static uint32_t srp_compute_rq_tmo(struct ib_qp_attr *qp_attr, int attr_mask) 2510c9b03c1aSBart Van Assche { 2511c9b03c1aSBart Van Assche uint64_t T_tr_ns, max_compl_time_ms; 2512c9b03c1aSBart Van Assche uint32_t rq_tmo_jiffies; 2513c9b03c1aSBart Van Assche 2514c9b03c1aSBart Van Assche /* 2515c9b03c1aSBart Van Assche * According to section 11.2.4.2 in the IBTA spec (Modify Queue Pair, 2516c9b03c1aSBart Van Assche * table 91), both the QP timeout and the retry count have to be set 2517c9b03c1aSBart Van Assche * for RC QP's during the RTR to RTS transition. 2518c9b03c1aSBart Van Assche */ 2519c9b03c1aSBart Van Assche WARN_ON_ONCE((attr_mask & (IB_QP_TIMEOUT | IB_QP_RETRY_CNT)) != 2520c9b03c1aSBart Van Assche (IB_QP_TIMEOUT | IB_QP_RETRY_CNT)); 2521c9b03c1aSBart Van Assche 2522c9b03c1aSBart Van Assche /* 2523c9b03c1aSBart Van Assche * Set target->rq_tmo_jiffies to one second more than the largest time 2524c9b03c1aSBart Van Assche * it can take before an error completion is generated. See also 2525c9b03c1aSBart Van Assche * C9-140..142 in the IBTA spec for more information about how to 2526c9b03c1aSBart Van Assche * convert the QP Local ACK Timeout value to nanoseconds. 2527c9b03c1aSBart Van Assche */ 2528c9b03c1aSBart Van Assche T_tr_ns = 4096 * (1ULL << qp_attr->timeout); 2529c9b03c1aSBart Van Assche max_compl_time_ms = qp_attr->retry_cnt * 4 * T_tr_ns; 2530c9b03c1aSBart Van Assche do_div(max_compl_time_ms, NSEC_PER_MSEC); 2531c9b03c1aSBart Van Assche rq_tmo_jiffies = msecs_to_jiffies(max_compl_time_ms + 1000); 2532c9b03c1aSBart Van Assche 2533c9b03c1aSBart Van Assche return rq_tmo_jiffies; 2534c9b03c1aSBart Van Assche } 2535c9b03c1aSBart Van Assche 2536961e0be8SDavid Dillow static void srp_cm_rep_handler(struct ib_cm_id *cm_id, 2537e6300cbdSBart Van Assche const struct srp_login_rsp *lrsp, 2538509c07bcSBart Van Assche struct srp_rdma_ch *ch) 2539961e0be8SDavid Dillow { 2540509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 2541961e0be8SDavid Dillow struct ib_qp_attr *qp_attr = NULL; 2542961e0be8SDavid Dillow int attr_mask = 0; 254319f31343SBart Van Assche int ret = 0; 2544961e0be8SDavid Dillow int i; 2545961e0be8SDavid Dillow 2546961e0be8SDavid Dillow if (lrsp->opcode == SRP_LOGIN_RSP) { 2547509c07bcSBart Van Assche ch->max_ti_iu_len = be32_to_cpu(lrsp->max_ti_iu_len); 2548509c07bcSBart Van Assche ch->req_lim = be32_to_cpu(lrsp->req_lim_delta); 2549882981f4SBart Van Assche ch->use_imm_data = lrsp->rsp_flags & SRP_LOGIN_RSP_IMMED_SUPP; 2550882981f4SBart Van Assche ch->max_it_iu_len = srp_max_it_iu_len(target->cmd_sg_cnt, 2551*b2e872f4SHonggang Li ch->use_imm_data, 2552*b2e872f4SHonggang Li target->max_it_iu_size); 2553513d5647SBart Van Assche WARN_ON_ONCE(ch->max_it_iu_len > 2554513d5647SBart Van Assche be32_to_cpu(lrsp->max_it_iu_len)); 2555961e0be8SDavid Dillow 2556882981f4SBart Van Assche if (ch->use_imm_data) 2557882981f4SBart Van Assche shost_printk(KERN_DEBUG, target->scsi_host, 2558882981f4SBart Van Assche PFX "using immediate data\n"); 2559961e0be8SDavid Dillow 2560961e0be8SDavid Dillow /* 2561961e0be8SDavid Dillow * Reserve credits for task management so we don't 2562961e0be8SDavid Dillow * bounce requests back to the SCSI mid-layer. 2563961e0be8SDavid Dillow */ 2564961e0be8SDavid Dillow target->scsi_host->can_queue 2565509c07bcSBart Van Assche = min(ch->req_lim - SRP_TSK_MGMT_SQ_SIZE, 2566961e0be8SDavid Dillow target->scsi_host->can_queue); 25674d73f95fSBart Van Assche target->scsi_host->cmd_per_lun 25684d73f95fSBart Van Assche = min_t(int, target->scsi_host->can_queue, 25694d73f95fSBart Van Assche target->scsi_host->cmd_per_lun); 2570961e0be8SDavid Dillow } else { 2571961e0be8SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 2572961e0be8SDavid Dillow PFX "Unhandled RSP opcode %#x\n", lrsp->opcode); 2573961e0be8SDavid Dillow ret = -ECONNRESET; 2574961e0be8SDavid Dillow goto error; 2575961e0be8SDavid Dillow } 2576961e0be8SDavid Dillow 2577509c07bcSBart Van Assche if (!ch->rx_ring) { 2578509c07bcSBart Van Assche ret = srp_alloc_iu_bufs(ch); 2579961e0be8SDavid Dillow if (ret) 2580961e0be8SDavid Dillow goto error; 2581961e0be8SDavid Dillow } 2582961e0be8SDavid Dillow 258319f31343SBart Van Assche for (i = 0; i < target->queue_size; i++) { 258419f31343SBart Van Assche struct srp_iu *iu = ch->rx_ring[i]; 258519f31343SBart Van Assche 258619f31343SBart Van Assche ret = srp_post_recv(ch, iu); 258719f31343SBart Van Assche if (ret) 258819f31343SBart Van Assche goto error; 258919f31343SBart Van Assche } 259019f31343SBart Van Assche 259119f31343SBart Van Assche if (!target->using_rdma_cm) { 2592961e0be8SDavid Dillow ret = -ENOMEM; 259319f31343SBart Van Assche qp_attr = kmalloc(sizeof(*qp_attr), GFP_KERNEL); 2594961e0be8SDavid Dillow if (!qp_attr) 2595961e0be8SDavid Dillow goto error; 2596961e0be8SDavid Dillow 2597961e0be8SDavid Dillow qp_attr->qp_state = IB_QPS_RTR; 2598961e0be8SDavid Dillow ret = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask); 2599961e0be8SDavid Dillow if (ret) 2600961e0be8SDavid Dillow goto error_free; 2601961e0be8SDavid Dillow 2602509c07bcSBart Van Assche ret = ib_modify_qp(ch->qp, qp_attr, attr_mask); 2603961e0be8SDavid Dillow if (ret) 2604961e0be8SDavid Dillow goto error_free; 2605961e0be8SDavid Dillow 2606961e0be8SDavid Dillow qp_attr->qp_state = IB_QPS_RTS; 2607961e0be8SDavid Dillow ret = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask); 2608961e0be8SDavid Dillow if (ret) 2609961e0be8SDavid Dillow goto error_free; 2610961e0be8SDavid Dillow 2611c9b03c1aSBart Van Assche target->rq_tmo_jiffies = srp_compute_rq_tmo(qp_attr, attr_mask); 2612c9b03c1aSBart Van Assche 2613509c07bcSBart Van Assche ret = ib_modify_qp(ch->qp, qp_attr, attr_mask); 2614961e0be8SDavid Dillow if (ret) 2615961e0be8SDavid Dillow goto error_free; 2616961e0be8SDavid Dillow 2617961e0be8SDavid Dillow ret = ib_send_cm_rtu(cm_id, NULL, 0); 261819f31343SBart Van Assche } 2619961e0be8SDavid Dillow 2620961e0be8SDavid Dillow error_free: 2621961e0be8SDavid Dillow kfree(qp_attr); 2622961e0be8SDavid Dillow 2623961e0be8SDavid Dillow error: 2624509c07bcSBart Van Assche ch->status = ret; 2625961e0be8SDavid Dillow } 2626961e0be8SDavid Dillow 262719f31343SBart Van Assche static void srp_ib_cm_rej_handler(struct ib_cm_id *cm_id, 2628e7ff98aeSParav Pandit const struct ib_cm_event *event, 2629509c07bcSBart Van Assche struct srp_rdma_ch *ch) 2630aef9ec39SRoland Dreier { 2631509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 26327aa54bd7SDavid Dillow struct Scsi_Host *shost = target->scsi_host; 2633aef9ec39SRoland Dreier struct ib_class_port_info *cpi; 2634aef9ec39SRoland Dreier int opcode; 263519f31343SBart Van Assche u16 dlid; 2636aef9ec39SRoland Dreier 2637aef9ec39SRoland Dreier switch (event->param.rej_rcvd.reason) { 2638aef9ec39SRoland Dreier case IB_CM_REJ_PORT_CM_REDIRECT: 2639aef9ec39SRoland Dreier cpi = event->param.rej_rcvd.ari; 264019f31343SBart Van Assche dlid = be16_to_cpu(cpi->redirect_lid); 264119f31343SBart Van Assche sa_path_set_dlid(&ch->ib_cm.path, dlid); 264219f31343SBart Van Assche ch->ib_cm.path.pkey = cpi->redirect_pkey; 2643aef9ec39SRoland Dreier cm_id->remote_cm_qpn = be32_to_cpu(cpi->redirect_qp) & 0x00ffffff; 264419f31343SBart Van Assche memcpy(ch->ib_cm.path.dgid.raw, cpi->redirect_gid, 16); 2645aef9ec39SRoland Dreier 264619f31343SBart Van Assche ch->status = dlid ? SRP_DLID_REDIRECT : SRP_PORT_REDIRECT; 2647aef9ec39SRoland Dreier break; 2648aef9ec39SRoland Dreier 2649aef9ec39SRoland Dreier case IB_CM_REJ_PORT_REDIRECT: 26505d7cbfd6SRoland Dreier if (srp_target_is_topspin(target)) { 265119f31343SBart Van Assche union ib_gid *dgid = &ch->ib_cm.path.dgid; 265219f31343SBart Van Assche 2653aef9ec39SRoland Dreier /* 2654aef9ec39SRoland Dreier * Topspin/Cisco SRP gateways incorrectly send 2655aef9ec39SRoland Dreier * reject reason code 25 when they mean 24 2656aef9ec39SRoland Dreier * (port redirect). 2657aef9ec39SRoland Dreier */ 265819f31343SBart Van Assche memcpy(dgid->raw, event->param.rej_rcvd.ari, 16); 2659aef9ec39SRoland Dreier 26607aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, shost, 26617aa54bd7SDavid Dillow PFX "Topspin/Cisco redirect to target port GID %016llx%016llx\n", 266219f31343SBart Van Assche be64_to_cpu(dgid->global.subnet_prefix), 266319f31343SBart Van Assche be64_to_cpu(dgid->global.interface_id)); 2664aef9ec39SRoland Dreier 2665509c07bcSBart Van Assche ch->status = SRP_PORT_REDIRECT; 2666aef9ec39SRoland Dreier } else { 26677aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, 26687aa54bd7SDavid Dillow " REJ reason: IB_CM_REJ_PORT_REDIRECT\n"); 2669509c07bcSBart Van Assche ch->status = -ECONNRESET; 2670aef9ec39SRoland Dreier } 2671aef9ec39SRoland Dreier break; 2672aef9ec39SRoland Dreier 2673aef9ec39SRoland Dreier case IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID: 26747aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, 26757aa54bd7SDavid Dillow " REJ reason: IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID\n"); 2676509c07bcSBart Van Assche ch->status = -ECONNRESET; 2677aef9ec39SRoland Dreier break; 2678aef9ec39SRoland Dreier 2679aef9ec39SRoland Dreier case IB_CM_REJ_CONSUMER_DEFINED: 2680aef9ec39SRoland Dreier opcode = *(u8 *) event->private_data; 2681aef9ec39SRoland Dreier if (opcode == SRP_LOGIN_REJ) { 2682aef9ec39SRoland Dreier struct srp_login_rej *rej = event->private_data; 2683aef9ec39SRoland Dreier u32 reason = be32_to_cpu(rej->reason); 2684aef9ec39SRoland Dreier 2685aef9ec39SRoland Dreier if (reason == SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE) 26867aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, 26877aa54bd7SDavid Dillow PFX "SRP_LOGIN_REJ: requested max_it_iu_len too large\n"); 2688aef9ec39SRoland Dreier else 2689e7ffde01SBart Van Assche shost_printk(KERN_WARNING, shost, PFX 2690e7ffde01SBart Van Assche "SRP LOGIN from %pI6 to %pI6 REJECTED, reason 0x%08x\n", 2691747fe000SBart Van Assche target->sgid.raw, 269219f31343SBart Van Assche target->ib_cm.orig_dgid.raw, 269319f31343SBart Van Assche reason); 2694aef9ec39SRoland Dreier } else 26957aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, 26967aa54bd7SDavid Dillow " REJ reason: IB_CM_REJ_CONSUMER_DEFINED," 2697aef9ec39SRoland Dreier " opcode 0x%02x\n", opcode); 2698509c07bcSBart Van Assche ch->status = -ECONNRESET; 2699aef9ec39SRoland Dreier break; 2700aef9ec39SRoland Dreier 27019fe4bcf4SDavid Dillow case IB_CM_REJ_STALE_CONN: 27029fe4bcf4SDavid Dillow shost_printk(KERN_WARNING, shost, " REJ reason: stale connection\n"); 2703509c07bcSBart Van Assche ch->status = SRP_STALE_CONN; 27049fe4bcf4SDavid Dillow break; 27059fe4bcf4SDavid Dillow 2706aef9ec39SRoland Dreier default: 27077aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, " REJ reason 0x%x\n", 2708aef9ec39SRoland Dreier event->param.rej_rcvd.reason); 2709509c07bcSBart Van Assche ch->status = -ECONNRESET; 2710aef9ec39SRoland Dreier } 2711aef9ec39SRoland Dreier } 2712aef9ec39SRoland Dreier 2713e7ff98aeSParav Pandit static int srp_ib_cm_handler(struct ib_cm_id *cm_id, 2714e7ff98aeSParav Pandit const struct ib_cm_event *event) 2715aef9ec39SRoland Dreier { 2716509c07bcSBart Van Assche struct srp_rdma_ch *ch = cm_id->context; 2717509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 2718aef9ec39SRoland Dreier int comp = 0; 2719aef9ec39SRoland Dreier 2720aef9ec39SRoland Dreier switch (event->event) { 2721aef9ec39SRoland Dreier case IB_CM_REQ_ERROR: 27227aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, target->scsi_host, 27237aa54bd7SDavid Dillow PFX "Sending CM REQ failed\n"); 2724aef9ec39SRoland Dreier comp = 1; 2725509c07bcSBart Van Assche ch->status = -ECONNRESET; 2726aef9ec39SRoland Dreier break; 2727aef9ec39SRoland Dreier 2728aef9ec39SRoland Dreier case IB_CM_REP_RECEIVED: 2729aef9ec39SRoland Dreier comp = 1; 2730509c07bcSBart Van Assche srp_cm_rep_handler(cm_id, event->private_data, ch); 2731aef9ec39SRoland Dreier break; 2732aef9ec39SRoland Dreier 2733aef9ec39SRoland Dreier case IB_CM_REJ_RECEIVED: 27347aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, target->scsi_host, PFX "REJ received\n"); 2735aef9ec39SRoland Dreier comp = 1; 2736aef9ec39SRoland Dreier 273719f31343SBart Van Assche srp_ib_cm_rej_handler(cm_id, event, ch); 2738aef9ec39SRoland Dreier break; 2739aef9ec39SRoland Dreier 2740b7ac4ab4SIshai Rabinovitz case IB_CM_DREQ_RECEIVED: 27417aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 27427aa54bd7SDavid Dillow PFX "DREQ received - connection closed\n"); 2743c014c8cdSBart Van Assche ch->connected = false; 2744b7ac4ab4SIshai Rabinovitz if (ib_send_cm_drep(cm_id, NULL, 0)) 27457aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 27467aa54bd7SDavid Dillow PFX "Sending CM DREP failed\n"); 2747c1120f89SBart Van Assche queue_work(system_long_wq, &target->tl_err_work); 2748aef9ec39SRoland Dreier break; 2749aef9ec39SRoland Dreier 2750aef9ec39SRoland Dreier case IB_CM_TIMEWAIT_EXIT: 27517aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 27527aa54bd7SDavid Dillow PFX "connection closed\n"); 2753ac72d766SBart Van Assche comp = 1; 2754aef9ec39SRoland Dreier 2755509c07bcSBart Van Assche ch->status = 0; 2756aef9ec39SRoland Dreier break; 2757aef9ec39SRoland Dreier 2758b7ac4ab4SIshai Rabinovitz case IB_CM_MRA_RECEIVED: 2759b7ac4ab4SIshai Rabinovitz case IB_CM_DREQ_ERROR: 2760b7ac4ab4SIshai Rabinovitz case IB_CM_DREP_RECEIVED: 2761b7ac4ab4SIshai Rabinovitz break; 2762b7ac4ab4SIshai Rabinovitz 2763aef9ec39SRoland Dreier default: 27647aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 27657aa54bd7SDavid Dillow PFX "Unhandled CM event %d\n", event->event); 2766aef9ec39SRoland Dreier break; 2767aef9ec39SRoland Dreier } 2768aef9ec39SRoland Dreier 2769aef9ec39SRoland Dreier if (comp) 2770509c07bcSBart Van Assche complete(&ch->done); 2771aef9ec39SRoland Dreier 2772aef9ec39SRoland Dreier return 0; 2773aef9ec39SRoland Dreier } 2774aef9ec39SRoland Dreier 277519f31343SBart Van Assche static void srp_rdma_cm_rej_handler(struct srp_rdma_ch *ch, 277619f31343SBart Van Assche struct rdma_cm_event *event) 277719f31343SBart Van Assche { 277819f31343SBart Van Assche struct srp_target_port *target = ch->target; 277919f31343SBart Van Assche struct Scsi_Host *shost = target->scsi_host; 278019f31343SBart Van Assche int opcode; 278119f31343SBart Van Assche 278219f31343SBart Van Assche switch (event->status) { 278319f31343SBart Van Assche case IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID: 278419f31343SBart Van Assche shost_printk(KERN_WARNING, shost, 278519f31343SBart Van Assche " REJ reason: IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID\n"); 278619f31343SBart Van Assche ch->status = -ECONNRESET; 278719f31343SBart Van Assche break; 278819f31343SBart Van Assche 278919f31343SBart Van Assche case IB_CM_REJ_CONSUMER_DEFINED: 279019f31343SBart Van Assche opcode = *(u8 *) event->param.conn.private_data; 279119f31343SBart Van Assche if (opcode == SRP_LOGIN_REJ) { 279219f31343SBart Van Assche struct srp_login_rej *rej = 279319f31343SBart Van Assche (struct srp_login_rej *) 279419f31343SBart Van Assche event->param.conn.private_data; 279519f31343SBart Van Assche u32 reason = be32_to_cpu(rej->reason); 279619f31343SBart Van Assche 279719f31343SBart Van Assche if (reason == SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE) 279819f31343SBart Van Assche shost_printk(KERN_WARNING, shost, 279919f31343SBart Van Assche PFX "SRP_LOGIN_REJ: requested max_it_iu_len too large\n"); 280019f31343SBart Van Assche else 280119f31343SBart Van Assche shost_printk(KERN_WARNING, shost, 280219f31343SBart Van Assche PFX "SRP LOGIN REJECTED, reason 0x%08x\n", reason); 280319f31343SBart Van Assche } else { 280419f31343SBart Van Assche shost_printk(KERN_WARNING, shost, 280519f31343SBart Van Assche " REJ reason: IB_CM_REJ_CONSUMER_DEFINED, opcode 0x%02x\n", 280619f31343SBart Van Assche opcode); 280719f31343SBart Van Assche } 280819f31343SBart Van Assche ch->status = -ECONNRESET; 280919f31343SBart Van Assche break; 281019f31343SBart Van Assche 281119f31343SBart Van Assche case IB_CM_REJ_STALE_CONN: 281219f31343SBart Van Assche shost_printk(KERN_WARNING, shost, 281319f31343SBart Van Assche " REJ reason: stale connection\n"); 281419f31343SBart Van Assche ch->status = SRP_STALE_CONN; 281519f31343SBart Van Assche break; 281619f31343SBart Van Assche 281719f31343SBart Van Assche default: 281819f31343SBart Van Assche shost_printk(KERN_WARNING, shost, " REJ reason 0x%x\n", 281919f31343SBart Van Assche event->status); 282019f31343SBart Van Assche ch->status = -ECONNRESET; 282119f31343SBart Van Assche break; 282219f31343SBart Van Assche } 282319f31343SBart Van Assche } 282419f31343SBart Van Assche 282519f31343SBart Van Assche static int srp_rdma_cm_handler(struct rdma_cm_id *cm_id, 282619f31343SBart Van Assche struct rdma_cm_event *event) 282719f31343SBart Van Assche { 282819f31343SBart Van Assche struct srp_rdma_ch *ch = cm_id->context; 282919f31343SBart Van Assche struct srp_target_port *target = ch->target; 283019f31343SBart Van Assche int comp = 0; 283119f31343SBart Van Assche 283219f31343SBart Van Assche switch (event->event) { 283319f31343SBart Van Assche case RDMA_CM_EVENT_ADDR_RESOLVED: 283419f31343SBart Van Assche ch->status = 0; 283519f31343SBart Van Assche comp = 1; 283619f31343SBart Van Assche break; 283719f31343SBart Van Assche 283819f31343SBart Van Assche case RDMA_CM_EVENT_ADDR_ERROR: 283919f31343SBart Van Assche ch->status = -ENXIO; 284019f31343SBart Van Assche comp = 1; 284119f31343SBart Van Assche break; 284219f31343SBart Van Assche 284319f31343SBart Van Assche case RDMA_CM_EVENT_ROUTE_RESOLVED: 284419f31343SBart Van Assche ch->status = 0; 284519f31343SBart Van Assche comp = 1; 284619f31343SBart Van Assche break; 284719f31343SBart Van Assche 284819f31343SBart Van Assche case RDMA_CM_EVENT_ROUTE_ERROR: 284919f31343SBart Van Assche case RDMA_CM_EVENT_UNREACHABLE: 285019f31343SBart Van Assche ch->status = -EHOSTUNREACH; 285119f31343SBart Van Assche comp = 1; 285219f31343SBart Van Assche break; 285319f31343SBart Van Assche 285419f31343SBart Van Assche case RDMA_CM_EVENT_CONNECT_ERROR: 285519f31343SBart Van Assche shost_printk(KERN_DEBUG, target->scsi_host, 285619f31343SBart Van Assche PFX "Sending CM REQ failed\n"); 285719f31343SBart Van Assche comp = 1; 285819f31343SBart Van Assche ch->status = -ECONNRESET; 285919f31343SBart Van Assche break; 286019f31343SBart Van Assche 286119f31343SBart Van Assche case RDMA_CM_EVENT_ESTABLISHED: 286219f31343SBart Van Assche comp = 1; 286319f31343SBart Van Assche srp_cm_rep_handler(NULL, event->param.conn.private_data, ch); 286419f31343SBart Van Assche break; 286519f31343SBart Van Assche 286619f31343SBart Van Assche case RDMA_CM_EVENT_REJECTED: 286719f31343SBart Van Assche shost_printk(KERN_DEBUG, target->scsi_host, PFX "REJ received\n"); 286819f31343SBart Van Assche comp = 1; 286919f31343SBart Van Assche 287019f31343SBart Van Assche srp_rdma_cm_rej_handler(ch, event); 287119f31343SBart Van Assche break; 287219f31343SBart Van Assche 287319f31343SBart Van Assche case RDMA_CM_EVENT_DISCONNECTED: 287419f31343SBart Van Assche if (ch->connected) { 287519f31343SBart Van Assche shost_printk(KERN_WARNING, target->scsi_host, 287619f31343SBart Van Assche PFX "received DREQ\n"); 287719f31343SBart Van Assche rdma_disconnect(ch->rdma_cm.cm_id); 287819f31343SBart Van Assche comp = 1; 287919f31343SBart Van Assche ch->status = 0; 288019f31343SBart Van Assche queue_work(system_long_wq, &target->tl_err_work); 288119f31343SBart Van Assche } 288219f31343SBart Van Assche break; 288319f31343SBart Van Assche 288419f31343SBart Van Assche case RDMA_CM_EVENT_TIMEWAIT_EXIT: 288519f31343SBart Van Assche shost_printk(KERN_ERR, target->scsi_host, 288619f31343SBart Van Assche PFX "connection closed\n"); 288719f31343SBart Van Assche 288819f31343SBart Van Assche comp = 1; 288919f31343SBart Van Assche ch->status = 0; 289019f31343SBart Van Assche break; 289119f31343SBart Van Assche 289219f31343SBart Van Assche default: 289319f31343SBart Van Assche shost_printk(KERN_WARNING, target->scsi_host, 289419f31343SBart Van Assche PFX "Unhandled CM event %d\n", event->event); 289519f31343SBart Van Assche break; 289619f31343SBart Van Assche } 289719f31343SBart Van Assche 289819f31343SBart Van Assche if (comp) 289919f31343SBart Van Assche complete(&ch->done); 290019f31343SBart Van Assche 290119f31343SBart Van Assche return 0; 290219f31343SBart Van Assche } 290319f31343SBart Van Assche 290471444b97SJack Wang /** 290571444b97SJack Wang * srp_change_queue_depth - setting device queue depth 290671444b97SJack Wang * @sdev: scsi device struct 290771444b97SJack Wang * @qdepth: requested queue depth 290871444b97SJack Wang * 290971444b97SJack Wang * Returns queue depth. 291071444b97SJack Wang */ 291171444b97SJack Wang static int 2912db5ed4dfSChristoph Hellwig srp_change_queue_depth(struct scsi_device *sdev, int qdepth) 291371444b97SJack Wang { 291471444b97SJack Wang if (!sdev->tagged_supported) 29151e6f2416SChristoph Hellwig qdepth = 1; 2916db5ed4dfSChristoph Hellwig return scsi_change_queue_depth(sdev, qdepth); 291771444b97SJack Wang } 291871444b97SJack Wang 2919985aa495SBart Van Assche static int srp_send_tsk_mgmt(struct srp_rdma_ch *ch, u64 req_tag, u64 lun, 29200a6fdbdeSBart Van Assche u8 func, u8 *status) 2921aef9ec39SRoland Dreier { 2922509c07bcSBart Van Assche struct srp_target_port *target = ch->target; 2923a95cadb9SBart Van Assche struct srp_rport *rport = target->rport; 292419081f31SDavid Dillow struct ib_device *dev = target->srp_host->srp_dev->dev; 2925aef9ec39SRoland Dreier struct srp_iu *iu; 2926aef9ec39SRoland Dreier struct srp_tsk_mgmt *tsk_mgmt; 29270a6fdbdeSBart Van Assche int res; 2928aef9ec39SRoland Dreier 2929c014c8cdSBart Van Assche if (!ch->connected || target->qp_in_error) 29303780d1f0SBart Van Assche return -1; 29313780d1f0SBart Van Assche 2932a95cadb9SBart Van Assche /* 2933509c07bcSBart Van Assche * Lock the rport mutex to avoid that srp_create_ch_ib() is 2934a95cadb9SBart Van Assche * invoked while a task management function is being sent. 2935a95cadb9SBart Van Assche */ 2936a95cadb9SBart Van Assche mutex_lock(&rport->mutex); 2937509c07bcSBart Van Assche spin_lock_irq(&ch->lock); 2938509c07bcSBart Van Assche iu = __srp_get_tx_iu(ch, SRP_IU_TSK_MGMT); 2939509c07bcSBart Van Assche spin_unlock_irq(&ch->lock); 294076c75b25SBart Van Assche 2941a95cadb9SBart Van Assche if (!iu) { 2942a95cadb9SBart Van Assche mutex_unlock(&rport->mutex); 2943a95cadb9SBart Van Assche 294476c75b25SBart Van Assche return -1; 2945a95cadb9SBart Van Assche } 2946aef9ec39SRoland Dreier 2947882981f4SBart Van Assche iu->num_sge = 1; 2948882981f4SBart Van Assche 294919081f31SDavid Dillow ib_dma_sync_single_for_cpu(dev, iu->dma, sizeof *tsk_mgmt, 295019081f31SDavid Dillow DMA_TO_DEVICE); 2951aef9ec39SRoland Dreier tsk_mgmt = iu->buf; 2952aef9ec39SRoland Dreier memset(tsk_mgmt, 0, sizeof *tsk_mgmt); 2953aef9ec39SRoland Dreier 2954aef9ec39SRoland Dreier tsk_mgmt->opcode = SRP_TSK_MGMT; 2955985aa495SBart Van Assche int_to_scsilun(lun, &tsk_mgmt->lun); 2956aef9ec39SRoland Dreier tsk_mgmt->tsk_mgmt_func = func; 2957f8b6e31eSDavid Dillow tsk_mgmt->task_tag = req_tag; 2958aef9ec39SRoland Dreier 29590a6fdbdeSBart Van Assche spin_lock_irq(&ch->lock); 29600a6fdbdeSBart Van Assche ch->tsk_mgmt_tag = (ch->tsk_mgmt_tag + 1) | SRP_TAG_TSK_MGMT; 29610a6fdbdeSBart Van Assche tsk_mgmt->tag = ch->tsk_mgmt_tag; 29620a6fdbdeSBart Van Assche spin_unlock_irq(&ch->lock); 29630a6fdbdeSBart Van Assche 29640a6fdbdeSBart Van Assche init_completion(&ch->tsk_mgmt_done); 29650a6fdbdeSBart Van Assche 296619081f31SDavid Dillow ib_dma_sync_single_for_device(dev, iu->dma, sizeof *tsk_mgmt, 296719081f31SDavid Dillow DMA_TO_DEVICE); 2968509c07bcSBart Van Assche if (srp_post_send(ch, iu, sizeof(*tsk_mgmt))) { 2969509c07bcSBart Van Assche srp_put_tx_iu(ch, iu, SRP_IU_TSK_MGMT); 2970a95cadb9SBart Van Assche mutex_unlock(&rport->mutex); 2971a95cadb9SBart Van Assche 297276c75b25SBart Van Assche return -1; 297376c75b25SBart Van Assche } 29740a6fdbdeSBart Van Assche res = wait_for_completion_timeout(&ch->tsk_mgmt_done, 29750a6fdbdeSBart Van Assche msecs_to_jiffies(SRP_ABORT_TIMEOUT_MS)); 29760a6fdbdeSBart Van Assche if (res > 0 && status) 29770a6fdbdeSBart Van Assche *status = ch->tsk_mgmt_status; 2978a95cadb9SBart Van Assche mutex_unlock(&rport->mutex); 2979d945e1dfSRoland Dreier 29800a6fdbdeSBart Van Assche WARN_ON_ONCE(res < 0); 2981aef9ec39SRoland Dreier 29820a6fdbdeSBart Van Assche return res > 0 ? 0 : -1; 2983d945e1dfSRoland Dreier } 2984d945e1dfSRoland Dreier 2985aef9ec39SRoland Dreier static int srp_abort(struct scsi_cmnd *scmnd) 2986aef9ec39SRoland Dreier { 2987d945e1dfSRoland Dreier struct srp_target_port *target = host_to_target(scmnd->device->host); 2988f8b6e31eSDavid Dillow struct srp_request *req = (struct srp_request *) scmnd->host_scribble; 298977f2c1a4SBart Van Assche u32 tag; 2990d92c0da7SBart Van Assche u16 ch_idx; 2991509c07bcSBart Van Assche struct srp_rdma_ch *ch; 2992086f44f5SBart Van Assche int ret; 2993d945e1dfSRoland Dreier 29947aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n"); 2995aef9ec39SRoland Dreier 2996d92c0da7SBart Van Assche if (!req) 299799b6697aSBart Van Assche return SUCCESS; 299877f2c1a4SBart Van Assche tag = blk_mq_unique_tag(scmnd->request); 2999d92c0da7SBart Van Assche ch_idx = blk_mq_unique_tag_to_hwq(tag); 3000d92c0da7SBart Van Assche if (WARN_ON_ONCE(ch_idx >= target->ch_count)) 3001d92c0da7SBart Van Assche return SUCCESS; 3002d92c0da7SBart Van Assche ch = &target->ch[ch_idx]; 3003d92c0da7SBart Van Assche if (!srp_claim_req(ch, req, NULL, scmnd)) 3004d92c0da7SBart Van Assche return SUCCESS; 3005d92c0da7SBart Van Assche shost_printk(KERN_ERR, target->scsi_host, 3006d92c0da7SBart Van Assche "Sending SRP abort for tag %#x\n", tag); 300777f2c1a4SBart Van Assche if (srp_send_tsk_mgmt(ch, tag, scmnd->device->lun, 30080a6fdbdeSBart Van Assche SRP_TSK_ABORT_TASK, NULL) == 0) 3009086f44f5SBart Van Assche ret = SUCCESS; 3010ed9b2264SBart Van Assche else if (target->rport->state == SRP_RPORT_LOST) 301199e1c139SBart Van Assche ret = FAST_IO_FAIL; 3012086f44f5SBart Van Assche else 3013086f44f5SBart Van Assche ret = FAILED; 3014e68088e7SBart Van Assche if (ret == SUCCESS) { 3015509c07bcSBart Van Assche srp_free_req(ch, req, scmnd, 0); 3016d945e1dfSRoland Dreier scmnd->result = DID_ABORT << 16; 3017d8536670SBart Van Assche scmnd->scsi_done(scmnd); 3018e68088e7SBart Van Assche } 3019d945e1dfSRoland Dreier 3020086f44f5SBart Van Assche return ret; 3021aef9ec39SRoland Dreier } 3022aef9ec39SRoland Dreier 3023aef9ec39SRoland Dreier static int srp_reset_device(struct scsi_cmnd *scmnd) 3024aef9ec39SRoland Dreier { 3025d945e1dfSRoland Dreier struct srp_target_port *target = host_to_target(scmnd->device->host); 3026d92c0da7SBart Van Assche struct srp_rdma_ch *ch; 30270a6fdbdeSBart Van Assche u8 status; 3028d945e1dfSRoland Dreier 30297aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, "SRP reset_device called\n"); 3030aef9ec39SRoland Dreier 3031d92c0da7SBart Van Assche ch = &target->ch[0]; 3032509c07bcSBart Van Assche if (srp_send_tsk_mgmt(ch, SRP_TAG_NO_REQ, scmnd->device->lun, 30330a6fdbdeSBart Van Assche SRP_TSK_LUN_RESET, &status)) 3034d945e1dfSRoland Dreier return FAILED; 30350a6fdbdeSBart Van Assche if (status) 3036d945e1dfSRoland Dreier return FAILED; 3037d945e1dfSRoland Dreier 3038d945e1dfSRoland Dreier return SUCCESS; 3039aef9ec39SRoland Dreier } 3040aef9ec39SRoland Dreier 3041aef9ec39SRoland Dreier static int srp_reset_host(struct scsi_cmnd *scmnd) 3042aef9ec39SRoland Dreier { 3043aef9ec39SRoland Dreier struct srp_target_port *target = host_to_target(scmnd->device->host); 3044aef9ec39SRoland Dreier 30457aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX "SRP reset_host called\n"); 3046aef9ec39SRoland Dreier 3047ed9b2264SBart Van Assche return srp_reconnect_rport(target->rport) == 0 ? SUCCESS : FAILED; 3048aef9ec39SRoland Dreier } 3049aef9ec39SRoland Dreier 3050b0780ee5SBart Van Assche static int srp_target_alloc(struct scsi_target *starget) 3051b0780ee5SBart Van Assche { 3052b0780ee5SBart Van Assche struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); 3053b0780ee5SBart Van Assche struct srp_target_port *target = host_to_target(shost); 3054b0780ee5SBart Van Assche 3055b0780ee5SBart Van Assche if (target->target_can_queue) 3056b0780ee5SBart Van Assche starget->can_queue = target->target_can_queue; 3057b0780ee5SBart Van Assche return 0; 3058b0780ee5SBart Van Assche } 3059b0780ee5SBart Van Assche 3060c9b03c1aSBart Van Assche static int srp_slave_configure(struct scsi_device *sdev) 3061c9b03c1aSBart Van Assche { 3062c9b03c1aSBart Van Assche struct Scsi_Host *shost = sdev->host; 3063c9b03c1aSBart Van Assche struct srp_target_port *target = host_to_target(shost); 3064c9b03c1aSBart Van Assche struct request_queue *q = sdev->request_queue; 3065c9b03c1aSBart Van Assche unsigned long timeout; 3066c9b03c1aSBart Van Assche 3067c9b03c1aSBart Van Assche if (sdev->type == TYPE_DISK) { 3068c9b03c1aSBart Van Assche timeout = max_t(unsigned, 30 * HZ, target->rq_tmo_jiffies); 3069c9b03c1aSBart Van Assche blk_queue_rq_timeout(q, timeout); 3070c9b03c1aSBart Van Assche } 3071c9b03c1aSBart Van Assche 3072c9b03c1aSBart Van Assche return 0; 3073c9b03c1aSBart Van Assche } 3074c9b03c1aSBart Van Assche 3075ee959b00STony Jones static ssize_t show_id_ext(struct device *dev, struct device_attribute *attr, 3076ee959b00STony Jones char *buf) 30776ecb0c84SRoland Dreier { 3078ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 30796ecb0c84SRoland Dreier 308045c37cadSBart Van Assche return sprintf(buf, "0x%016llx\n", be64_to_cpu(target->id_ext)); 30816ecb0c84SRoland Dreier } 30826ecb0c84SRoland Dreier 3083ee959b00STony Jones static ssize_t show_ioc_guid(struct device *dev, struct device_attribute *attr, 3084ee959b00STony Jones char *buf) 30856ecb0c84SRoland Dreier { 3086ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 30876ecb0c84SRoland Dreier 308845c37cadSBart Van Assche return sprintf(buf, "0x%016llx\n", be64_to_cpu(target->ioc_guid)); 30896ecb0c84SRoland Dreier } 30906ecb0c84SRoland Dreier 3091ee959b00STony Jones static ssize_t show_service_id(struct device *dev, 3092ee959b00STony Jones struct device_attribute *attr, char *buf) 30936ecb0c84SRoland Dreier { 3094ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 30956ecb0c84SRoland Dreier 309619f31343SBart Van Assche if (target->using_rdma_cm) 309719f31343SBart Van Assche return -ENOENT; 309819f31343SBart Van Assche return sprintf(buf, "0x%016llx\n", 309919f31343SBart Van Assche be64_to_cpu(target->ib_cm.service_id)); 31006ecb0c84SRoland Dreier } 31016ecb0c84SRoland Dreier 3102ee959b00STony Jones static ssize_t show_pkey(struct device *dev, struct device_attribute *attr, 3103ee959b00STony Jones char *buf) 31046ecb0c84SRoland Dreier { 3105ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 31066ecb0c84SRoland Dreier 310719f31343SBart Van Assche if (target->using_rdma_cm) 310819f31343SBart Van Assche return -ENOENT; 310919f31343SBart Van Assche return sprintf(buf, "0x%04x\n", be16_to_cpu(target->ib_cm.pkey)); 31106ecb0c84SRoland Dreier } 31116ecb0c84SRoland Dreier 3112848b3082SBart Van Assche static ssize_t show_sgid(struct device *dev, struct device_attribute *attr, 3113848b3082SBart Van Assche char *buf) 3114848b3082SBart Van Assche { 3115848b3082SBart Van Assche struct srp_target_port *target = host_to_target(class_to_shost(dev)); 3116848b3082SBart Van Assche 3117747fe000SBart Van Assche return sprintf(buf, "%pI6\n", target->sgid.raw); 3118848b3082SBart Van Assche } 3119848b3082SBart Van Assche 3120ee959b00STony Jones static ssize_t show_dgid(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)); 3124d92c0da7SBart Van Assche struct srp_rdma_ch *ch = &target->ch[0]; 31256ecb0c84SRoland Dreier 312619f31343SBart Van Assche if (target->using_rdma_cm) 312719f31343SBart Van Assche return -ENOENT; 312819f31343SBart Van Assche return sprintf(buf, "%pI6\n", ch->ib_cm.path.dgid.raw); 31296ecb0c84SRoland Dreier } 31306ecb0c84SRoland Dreier 3131ee959b00STony Jones static ssize_t show_orig_dgid(struct device *dev, 3132ee959b00STony Jones struct device_attribute *attr, char *buf) 31333633b3d0SIshai Rabinovitz { 3134ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 31353633b3d0SIshai Rabinovitz 313619f31343SBart Van Assche if (target->using_rdma_cm) 313719f31343SBart Van Assche return -ENOENT; 313819f31343SBart Van Assche return sprintf(buf, "%pI6\n", target->ib_cm.orig_dgid.raw); 31393633b3d0SIshai Rabinovitz } 31403633b3d0SIshai Rabinovitz 314189de7486SBart Van Assche static ssize_t show_req_lim(struct device *dev, 314289de7486SBart Van Assche struct device_attribute *attr, char *buf) 314389de7486SBart Van Assche { 314489de7486SBart Van Assche struct srp_target_port *target = host_to_target(class_to_shost(dev)); 3145d92c0da7SBart Van Assche struct srp_rdma_ch *ch; 3146d92c0da7SBart Van Assche int i, req_lim = INT_MAX; 314789de7486SBart Van Assche 3148d92c0da7SBart Van Assche for (i = 0; i < target->ch_count; i++) { 3149d92c0da7SBart Van Assche ch = &target->ch[i]; 3150d92c0da7SBart Van Assche req_lim = min(req_lim, ch->req_lim); 3151d92c0da7SBart Van Assche } 3152d92c0da7SBart Van Assche return sprintf(buf, "%d\n", req_lim); 315389de7486SBart Van Assche } 315489de7486SBart Van Assche 3155ee959b00STony Jones static ssize_t show_zero_req_lim(struct device *dev, 3156ee959b00STony Jones struct device_attribute *attr, char *buf) 31576bfa24faSRoland Dreier { 3158ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 31596bfa24faSRoland Dreier 31606bfa24faSRoland Dreier return sprintf(buf, "%d\n", target->zero_req_lim); 31616bfa24faSRoland Dreier } 31626bfa24faSRoland Dreier 3163ee959b00STony Jones static ssize_t show_local_ib_port(struct device *dev, 3164ee959b00STony Jones struct device_attribute *attr, char *buf) 3165ded7f1a1SIshai Rabinovitz { 3166ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 3167ded7f1a1SIshai Rabinovitz 3168ded7f1a1SIshai Rabinovitz return sprintf(buf, "%d\n", target->srp_host->port); 3169ded7f1a1SIshai Rabinovitz } 3170ded7f1a1SIshai Rabinovitz 3171ee959b00STony Jones static ssize_t show_local_ib_device(struct device *dev, 3172ee959b00STony Jones struct device_attribute *attr, char *buf) 3173ded7f1a1SIshai Rabinovitz { 3174ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 3175ded7f1a1SIshai Rabinovitz 31766c854111SJason Gunthorpe return sprintf(buf, "%s\n", 31776c854111SJason Gunthorpe dev_name(&target->srp_host->srp_dev->dev->dev)); 3178ded7f1a1SIshai Rabinovitz } 3179ded7f1a1SIshai Rabinovitz 3180d92c0da7SBart Van Assche static ssize_t show_ch_count(struct device *dev, struct device_attribute *attr, 3181d92c0da7SBart Van Assche char *buf) 3182d92c0da7SBart Van Assche { 3183d92c0da7SBart Van Assche struct srp_target_port *target = host_to_target(class_to_shost(dev)); 3184d92c0da7SBart Van Assche 3185d92c0da7SBart Van Assche return sprintf(buf, "%d\n", target->ch_count); 3186d92c0da7SBart Van Assche } 3187d92c0da7SBart Van Assche 31884b5e5f41SBart Van Assche static ssize_t show_comp_vector(struct device *dev, 31894b5e5f41SBart Van Assche struct device_attribute *attr, char *buf) 31904b5e5f41SBart Van Assche { 31914b5e5f41SBart Van Assche struct srp_target_port *target = host_to_target(class_to_shost(dev)); 31924b5e5f41SBart Van Assche 31934b5e5f41SBart Van Assche return sprintf(buf, "%d\n", target->comp_vector); 31944b5e5f41SBart Van Assche } 31954b5e5f41SBart Van Assche 31967bb312e4SVu Pham static ssize_t show_tl_retry_count(struct device *dev, 31977bb312e4SVu Pham struct device_attribute *attr, char *buf) 31987bb312e4SVu Pham { 31997bb312e4SVu Pham struct srp_target_port *target = host_to_target(class_to_shost(dev)); 32007bb312e4SVu Pham 32017bb312e4SVu Pham return sprintf(buf, "%d\n", target->tl_retry_count); 32027bb312e4SVu Pham } 32037bb312e4SVu Pham 320449248644SDavid Dillow static ssize_t show_cmd_sg_entries(struct device *dev, 320549248644SDavid Dillow struct device_attribute *attr, char *buf) 320649248644SDavid Dillow { 320749248644SDavid Dillow struct srp_target_port *target = host_to_target(class_to_shost(dev)); 320849248644SDavid Dillow 320949248644SDavid Dillow return sprintf(buf, "%u\n", target->cmd_sg_cnt); 321049248644SDavid Dillow } 321149248644SDavid Dillow 3212c07d424dSDavid Dillow static ssize_t show_allow_ext_sg(struct device *dev, 3213c07d424dSDavid Dillow struct device_attribute *attr, char *buf) 3214c07d424dSDavid Dillow { 3215c07d424dSDavid Dillow struct srp_target_port *target = host_to_target(class_to_shost(dev)); 3216c07d424dSDavid Dillow 3217c07d424dSDavid Dillow return sprintf(buf, "%s\n", target->allow_ext_sg ? "true" : "false"); 3218c07d424dSDavid Dillow } 3219c07d424dSDavid Dillow 3220ee959b00STony Jones static DEVICE_ATTR(id_ext, S_IRUGO, show_id_ext, NULL); 3221ee959b00STony Jones static DEVICE_ATTR(ioc_guid, S_IRUGO, show_ioc_guid, NULL); 3222ee959b00STony Jones static DEVICE_ATTR(service_id, S_IRUGO, show_service_id, NULL); 3223ee959b00STony Jones static DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL); 3224848b3082SBart Van Assche static DEVICE_ATTR(sgid, S_IRUGO, show_sgid, NULL); 3225ee959b00STony Jones static DEVICE_ATTR(dgid, S_IRUGO, show_dgid, NULL); 3226ee959b00STony Jones static DEVICE_ATTR(orig_dgid, S_IRUGO, show_orig_dgid, NULL); 322789de7486SBart Van Assche static DEVICE_ATTR(req_lim, S_IRUGO, show_req_lim, NULL); 3228ee959b00STony Jones static DEVICE_ATTR(zero_req_lim, S_IRUGO, show_zero_req_lim, NULL); 3229ee959b00STony Jones static DEVICE_ATTR(local_ib_port, S_IRUGO, show_local_ib_port, NULL); 3230ee959b00STony Jones static DEVICE_ATTR(local_ib_device, S_IRUGO, show_local_ib_device, NULL); 3231d92c0da7SBart Van Assche static DEVICE_ATTR(ch_count, S_IRUGO, show_ch_count, NULL); 32324b5e5f41SBart Van Assche static DEVICE_ATTR(comp_vector, S_IRUGO, show_comp_vector, NULL); 32337bb312e4SVu Pham static DEVICE_ATTR(tl_retry_count, S_IRUGO, show_tl_retry_count, NULL); 323449248644SDavid Dillow static DEVICE_ATTR(cmd_sg_entries, S_IRUGO, show_cmd_sg_entries, NULL); 3235c07d424dSDavid Dillow static DEVICE_ATTR(allow_ext_sg, S_IRUGO, show_allow_ext_sg, NULL); 32366ecb0c84SRoland Dreier 3237ee959b00STony Jones static struct device_attribute *srp_host_attrs[] = { 3238ee959b00STony Jones &dev_attr_id_ext, 3239ee959b00STony Jones &dev_attr_ioc_guid, 3240ee959b00STony Jones &dev_attr_service_id, 3241ee959b00STony Jones &dev_attr_pkey, 3242848b3082SBart Van Assche &dev_attr_sgid, 3243ee959b00STony Jones &dev_attr_dgid, 3244ee959b00STony Jones &dev_attr_orig_dgid, 324589de7486SBart Van Assche &dev_attr_req_lim, 3246ee959b00STony Jones &dev_attr_zero_req_lim, 3247ee959b00STony Jones &dev_attr_local_ib_port, 3248ee959b00STony Jones &dev_attr_local_ib_device, 3249d92c0da7SBart Van Assche &dev_attr_ch_count, 32504b5e5f41SBart Van Assche &dev_attr_comp_vector, 32517bb312e4SVu Pham &dev_attr_tl_retry_count, 325249248644SDavid Dillow &dev_attr_cmd_sg_entries, 3253c07d424dSDavid Dillow &dev_attr_allow_ext_sg, 32546ecb0c84SRoland Dreier NULL 32556ecb0c84SRoland Dreier }; 32566ecb0c84SRoland Dreier 3257aef9ec39SRoland Dreier static struct scsi_host_template srp_template = { 3258aef9ec39SRoland Dreier .module = THIS_MODULE, 3259b7f008fdSRoland Dreier .name = "InfiniBand SRP initiator", 3260b7f008fdSRoland Dreier .proc_name = DRV_NAME, 3261b0780ee5SBart Van Assche .target_alloc = srp_target_alloc, 3262c9b03c1aSBart Van Assche .slave_configure = srp_slave_configure, 3263aef9ec39SRoland Dreier .info = srp_target_info, 3264aef9ec39SRoland Dreier .queuecommand = srp_queuecommand, 326571444b97SJack Wang .change_queue_depth = srp_change_queue_depth, 3266b6a05c82SChristoph Hellwig .eh_timed_out = srp_timed_out, 3267aef9ec39SRoland Dreier .eh_abort_handler = srp_abort, 3268aef9ec39SRoland Dreier .eh_device_reset_handler = srp_reset_device, 3269aef9ec39SRoland Dreier .eh_host_reset_handler = srp_reset_host, 32702742c1daSBart Van Assche .skip_settle_delay = true, 327149248644SDavid Dillow .sg_tablesize = SRP_DEF_SG_TABLESIZE, 32724d73f95fSBart Van Assche .can_queue = SRP_DEFAULT_CMD_SQ_SIZE, 3273aef9ec39SRoland Dreier .this_id = -1, 32744d73f95fSBart Van Assche .cmd_per_lun = SRP_DEFAULT_CMD_SQ_SIZE, 327577f2c1a4SBart Van Assche .shost_attrs = srp_host_attrs, 3276c40ecc12SChristoph Hellwig .track_queue_depth = 1, 3277aef9ec39SRoland Dreier }; 3278aef9ec39SRoland Dreier 327934aa654eSBart Van Assche static int srp_sdev_count(struct Scsi_Host *host) 328034aa654eSBart Van Assche { 328134aa654eSBart Van Assche struct scsi_device *sdev; 328234aa654eSBart Van Assche int c = 0; 328334aa654eSBart Van Assche 328434aa654eSBart Van Assche shost_for_each_device(sdev, host) 328534aa654eSBart Van Assche c++; 328634aa654eSBart Van Assche 328734aa654eSBart Van Assche return c; 328834aa654eSBart Van Assche } 328934aa654eSBart Van Assche 3290bc44bd1dSBart Van Assche /* 3291bc44bd1dSBart Van Assche * Return values: 3292bc44bd1dSBart Van Assche * < 0 upon failure. Caller is responsible for SRP target port cleanup. 3293bc44bd1dSBart Van Assche * 0 and target->state == SRP_TARGET_REMOVED if asynchronous target port 3294bc44bd1dSBart Van Assche * removal has been scheduled. 3295bc44bd1dSBart Van Assche * 0 and target->state != SRP_TARGET_REMOVED upon success. 3296bc44bd1dSBart Van Assche */ 3297aef9ec39SRoland Dreier static int srp_add_target(struct srp_host *host, struct srp_target_port *target) 3298aef9ec39SRoland Dreier { 32993236822bSFUJITA Tomonori struct srp_rport_identifiers ids; 33003236822bSFUJITA Tomonori struct srp_rport *rport; 33013236822bSFUJITA Tomonori 330234aa654eSBart Van Assche target->state = SRP_TARGET_SCANNING; 3303aef9ec39SRoland Dreier sprintf(target->target_name, "SRP.T10:%016llX", 330445c37cadSBart Van Assche be64_to_cpu(target->id_ext)); 3305aef9ec39SRoland Dreier 3306dee2b82aSBart Van Assche if (scsi_add_host(target->scsi_host, host->srp_dev->dev->dev.parent)) 3307aef9ec39SRoland Dreier return -ENODEV; 3308aef9ec39SRoland Dreier 33093236822bSFUJITA Tomonori memcpy(ids.port_id, &target->id_ext, 8); 33103236822bSFUJITA Tomonori memcpy(ids.port_id + 8, &target->ioc_guid, 8); 3311aebd5e47SFUJITA Tomonori ids.roles = SRP_RPORT_ROLE_TARGET; 33123236822bSFUJITA Tomonori rport = srp_rport_add(target->scsi_host, &ids); 33133236822bSFUJITA Tomonori if (IS_ERR(rport)) { 33143236822bSFUJITA Tomonori scsi_remove_host(target->scsi_host); 33153236822bSFUJITA Tomonori return PTR_ERR(rport); 33163236822bSFUJITA Tomonori } 33173236822bSFUJITA Tomonori 3318dc1bdbd9SBart Van Assche rport->lld_data = target; 33199dd69a60SBart Van Assche target->rport = rport; 3320dc1bdbd9SBart Van Assche 3321b3589fd4SMatthew Wilcox spin_lock(&host->target_lock); 3322aef9ec39SRoland Dreier list_add_tail(&target->list, &host->target_list); 3323b3589fd4SMatthew Wilcox spin_unlock(&host->target_lock); 3324aef9ec39SRoland Dreier 3325aef9ec39SRoland Dreier scsi_scan_target(&target->scsi_host->shost_gendev, 33261d645088SHannes Reinecke 0, target->scsi_id, SCAN_WILD_CARD, SCSI_SCAN_INITIAL); 3327aef9ec39SRoland Dreier 3328c014c8cdSBart Van Assche if (srp_connected_ch(target) < target->ch_count || 3329c014c8cdSBart Van Assche target->qp_in_error) { 333034aa654eSBart Van Assche shost_printk(KERN_INFO, target->scsi_host, 333134aa654eSBart Van Assche PFX "SCSI scan failed - removing SCSI host\n"); 333234aa654eSBart Van Assche srp_queue_remove_work(target); 333334aa654eSBart Van Assche goto out; 333434aa654eSBart Van Assche } 333534aa654eSBart Van Assche 3336cf1acab7SBart Van Assche pr_debug("%s: SCSI scan succeeded - detected %d LUNs\n", 333734aa654eSBart Van Assche dev_name(&target->scsi_host->shost_gendev), 333834aa654eSBart Van Assche srp_sdev_count(target->scsi_host)); 333934aa654eSBart Van Assche 334034aa654eSBart Van Assche spin_lock_irq(&target->lock); 334134aa654eSBart Van Assche if (target->state == SRP_TARGET_SCANNING) 334234aa654eSBart Van Assche target->state = SRP_TARGET_LIVE; 334334aa654eSBart Van Assche spin_unlock_irq(&target->lock); 334434aa654eSBart Van Assche 334534aa654eSBart Van Assche out: 3346aef9ec39SRoland Dreier return 0; 3347aef9ec39SRoland Dreier } 3348aef9ec39SRoland Dreier 3349ee959b00STony Jones static void srp_release_dev(struct device *dev) 3350aef9ec39SRoland Dreier { 3351aef9ec39SRoland Dreier struct srp_host *host = 3352ee959b00STony Jones container_of(dev, struct srp_host, dev); 3353aef9ec39SRoland Dreier 3354aef9ec39SRoland Dreier complete(&host->released); 3355aef9ec39SRoland Dreier } 3356aef9ec39SRoland Dreier 3357aef9ec39SRoland Dreier static struct class srp_class = { 3358aef9ec39SRoland Dreier .name = "infiniband_srp", 3359ee959b00STony Jones .dev_release = srp_release_dev 3360aef9ec39SRoland Dreier }; 3361aef9ec39SRoland Dreier 336296fc248aSBart Van Assche /** 336396fc248aSBart Van Assche * srp_conn_unique() - check whether the connection to a target is unique 3364af24663bSBart Van Assche * @host: SRP host. 3365af24663bSBart Van Assche * @target: SRP target port. 336696fc248aSBart Van Assche */ 336796fc248aSBart Van Assche static bool srp_conn_unique(struct srp_host *host, 336896fc248aSBart Van Assche struct srp_target_port *target) 336996fc248aSBart Van Assche { 337096fc248aSBart Van Assche struct srp_target_port *t; 337196fc248aSBart Van Assche bool ret = false; 337296fc248aSBart Van Assche 337396fc248aSBart Van Assche if (target->state == SRP_TARGET_REMOVED) 337496fc248aSBart Van Assche goto out; 337596fc248aSBart Van Assche 337696fc248aSBart Van Assche ret = true; 337796fc248aSBart Van Assche 337896fc248aSBart Van Assche spin_lock(&host->target_lock); 337996fc248aSBart Van Assche list_for_each_entry(t, &host->target_list, list) { 338096fc248aSBart Van Assche if (t != target && 338196fc248aSBart Van Assche target->id_ext == t->id_ext && 338296fc248aSBart Van Assche target->ioc_guid == t->ioc_guid && 338396fc248aSBart Van Assche target->initiator_ext == t->initiator_ext) { 338496fc248aSBart Van Assche ret = false; 338596fc248aSBart Van Assche break; 338696fc248aSBart Van Assche } 338796fc248aSBart Van Assche } 338896fc248aSBart Van Assche spin_unlock(&host->target_lock); 338996fc248aSBart Van Assche 339096fc248aSBart Van Assche out: 339196fc248aSBart Van Assche return ret; 339296fc248aSBart Van Assche } 339396fc248aSBart Van Assche 3394aef9ec39SRoland Dreier /* 3395aef9ec39SRoland Dreier * Target ports are added by writing 3396aef9ec39SRoland Dreier * 3397aef9ec39SRoland Dreier * id_ext=<SRP ID ext>,ioc_guid=<SRP IOC GUID>,dgid=<dest GID>, 3398aef9ec39SRoland Dreier * pkey=<P_Key>,service_id=<service ID> 339919f31343SBart Van Assche * or 340019f31343SBart Van Assche * id_ext=<SRP ID ext>,ioc_guid=<SRP IOC GUID>, 340119f31343SBart Van Assche * [src=<IPv4 address>,]dest=<IPv4 address>:<port number> 3402aef9ec39SRoland Dreier * 3403aef9ec39SRoland Dreier * to the add_target sysfs attribute. 3404aef9ec39SRoland Dreier */ 3405aef9ec39SRoland Dreier enum { 3406aef9ec39SRoland Dreier SRP_OPT_ERR = 0, 3407aef9ec39SRoland Dreier SRP_OPT_ID_EXT = 1 << 0, 3408aef9ec39SRoland Dreier SRP_OPT_IOC_GUID = 1 << 1, 3409aef9ec39SRoland Dreier SRP_OPT_DGID = 1 << 2, 3410aef9ec39SRoland Dreier SRP_OPT_PKEY = 1 << 3, 3411aef9ec39SRoland Dreier SRP_OPT_SERVICE_ID = 1 << 4, 3412aef9ec39SRoland Dreier SRP_OPT_MAX_SECT = 1 << 5, 341352fb2b50SVu Pham SRP_OPT_MAX_CMD_PER_LUN = 1 << 6, 34140c0450dbSRamachandra K SRP_OPT_IO_CLASS = 1 << 7, 341501cb9bcbSIshai Rabinovitz SRP_OPT_INITIATOR_EXT = 1 << 8, 341649248644SDavid Dillow SRP_OPT_CMD_SG_ENTRIES = 1 << 9, 3417c07d424dSDavid Dillow SRP_OPT_ALLOW_EXT_SG = 1 << 10, 3418c07d424dSDavid Dillow SRP_OPT_SG_TABLESIZE = 1 << 11, 34194b5e5f41SBart Van Assche SRP_OPT_COMP_VECTOR = 1 << 12, 34207bb312e4SVu Pham SRP_OPT_TL_RETRY_COUNT = 1 << 13, 34214d73f95fSBart Van Assche SRP_OPT_QUEUE_SIZE = 1 << 14, 342219f31343SBart Van Assche SRP_OPT_IP_SRC = 1 << 15, 342319f31343SBart Van Assche SRP_OPT_IP_DEST = 1 << 16, 3424b0780ee5SBart Van Assche SRP_OPT_TARGET_CAN_QUEUE= 1 << 17, 3425547ed331SHonggang Li SRP_OPT_MAX_IT_IU_SIZE = 1 << 18, 342619f31343SBart Van Assche }; 342719f31343SBart Van Assche 342819f31343SBart Van Assche static unsigned int srp_opt_mandatory[] = { 342919f31343SBart Van Assche SRP_OPT_ID_EXT | 3430aef9ec39SRoland Dreier SRP_OPT_IOC_GUID | 3431aef9ec39SRoland Dreier SRP_OPT_DGID | 3432aef9ec39SRoland Dreier SRP_OPT_PKEY | 343319f31343SBart Van Assche SRP_OPT_SERVICE_ID, 343419f31343SBart Van Assche SRP_OPT_ID_EXT | 343519f31343SBart Van Assche SRP_OPT_IOC_GUID | 343619f31343SBart Van Assche SRP_OPT_IP_DEST, 3437aef9ec39SRoland Dreier }; 3438aef9ec39SRoland Dreier 3439a447c093SSteven Whitehouse static const match_table_t srp_opt_tokens = { 3440aef9ec39SRoland Dreier { SRP_OPT_ID_EXT, "id_ext=%s" }, 3441aef9ec39SRoland Dreier { SRP_OPT_IOC_GUID, "ioc_guid=%s" }, 3442aef9ec39SRoland Dreier { SRP_OPT_DGID, "dgid=%s" }, 3443aef9ec39SRoland Dreier { SRP_OPT_PKEY, "pkey=%x" }, 3444aef9ec39SRoland Dreier { SRP_OPT_SERVICE_ID, "service_id=%s" }, 3445aef9ec39SRoland Dreier { SRP_OPT_MAX_SECT, "max_sect=%d" }, 344652fb2b50SVu Pham { SRP_OPT_MAX_CMD_PER_LUN, "max_cmd_per_lun=%d" }, 3447b0780ee5SBart Van Assche { SRP_OPT_TARGET_CAN_QUEUE, "target_can_queue=%d" }, 34480c0450dbSRamachandra K { SRP_OPT_IO_CLASS, "io_class=%x" }, 344901cb9bcbSIshai Rabinovitz { SRP_OPT_INITIATOR_EXT, "initiator_ext=%s" }, 345049248644SDavid Dillow { SRP_OPT_CMD_SG_ENTRIES, "cmd_sg_entries=%u" }, 3451c07d424dSDavid Dillow { SRP_OPT_ALLOW_EXT_SG, "allow_ext_sg=%u" }, 3452c07d424dSDavid Dillow { SRP_OPT_SG_TABLESIZE, "sg_tablesize=%u" }, 34534b5e5f41SBart Van Assche { SRP_OPT_COMP_VECTOR, "comp_vector=%u" }, 34547bb312e4SVu Pham { SRP_OPT_TL_RETRY_COUNT, "tl_retry_count=%u" }, 34554d73f95fSBart Van Assche { SRP_OPT_QUEUE_SIZE, "queue_size=%d" }, 345619f31343SBart Van Assche { SRP_OPT_IP_SRC, "src=%s" }, 345719f31343SBart Van Assche { SRP_OPT_IP_DEST, "dest=%s" }, 3458547ed331SHonggang Li { SRP_OPT_MAX_IT_IU_SIZE, "max_it_iu_size=%d" }, 3459aef9ec39SRoland Dreier { SRP_OPT_ERR, NULL } 3460aef9ec39SRoland Dreier }; 3461aef9ec39SRoland Dreier 3462c62adb7dSBart Van Assche /** 3463c62adb7dSBart Van Assche * srp_parse_in - parse an IP address and port number combination 3464e37df2d5SBart Van Assche * @net: [in] Network namespace. 3465e37df2d5SBart Van Assche * @sa: [out] Address family, IP address and port number. 3466e37df2d5SBart Van Assche * @addr_port_str: [in] IP address and port number. 3467bcef5b72SBart Van Assche * @has_port: [out] Whether or not @addr_port_str includes a port number. 3468c62adb7dSBart Van Assche * 3469c62adb7dSBart Van Assche * Parse the following address formats: 3470c62adb7dSBart Van Assche * - IPv4: <ip_address>:<port>, e.g. 1.2.3.4:5. 3471c62adb7dSBart Van Assche * - IPv6: \[<ipv6_address>\]:<port>, e.g. [1::2:3%4]:5. 3472c62adb7dSBart Van Assche */ 347319f31343SBart Van Assche static int srp_parse_in(struct net *net, struct sockaddr_storage *sa, 3474bcef5b72SBart Van Assche const char *addr_port_str, bool *has_port) 347519f31343SBart Van Assche { 3476c62adb7dSBart Van Assche char *addr_end, *addr = kstrdup(addr_port_str, GFP_KERNEL); 3477c62adb7dSBart Van Assche char *port_str; 347819f31343SBart Van Assche int ret; 347919f31343SBart Van Assche 348019f31343SBart Van Assche if (!addr) 348119f31343SBart Van Assche return -ENOMEM; 3482c62adb7dSBart Van Assche port_str = strrchr(addr, ':'); 3483bcef5b72SBart Van Assche if (port_str && strchr(port_str, ']')) 3484bcef5b72SBart Van Assche port_str = NULL; 3485bcef5b72SBart Van Assche if (port_str) 3486c62adb7dSBart Van Assche *port_str++ = '\0'; 3487bcef5b72SBart Van Assche if (has_port) 3488bcef5b72SBart Van Assche *has_port = port_str != NULL; 3489c62adb7dSBart Van Assche ret = inet_pton_with_scope(net, AF_INET, addr, port_str, sa); 3490c62adb7dSBart Van Assche if (ret && addr[0]) { 3491c62adb7dSBart Van Assche addr_end = addr + strlen(addr) - 1; 3492c62adb7dSBart Van Assche if (addr[0] == '[' && *addr_end == ']') { 3493c62adb7dSBart Van Assche *addr_end = '\0'; 3494c62adb7dSBart Van Assche ret = inet_pton_with_scope(net, AF_INET6, addr + 1, 3495c62adb7dSBart Van Assche port_str, sa); 3496c62adb7dSBart Van Assche } 3497c62adb7dSBart Van Assche } 349819f31343SBart Van Assche kfree(addr); 3499c62adb7dSBart Van Assche pr_debug("%s -> %pISpfsc\n", addr_port_str, sa); 350019f31343SBart Van Assche return ret; 350119f31343SBart Van Assche } 350219f31343SBart Van Assche 350319f31343SBart Van Assche static int srp_parse_options(struct net *net, const char *buf, 350419f31343SBart Van Assche struct srp_target_port *target) 3505aef9ec39SRoland Dreier { 3506aef9ec39SRoland Dreier char *options, *sep_opt; 3507aef9ec39SRoland Dreier char *p; 3508aef9ec39SRoland Dreier substring_t args[MAX_OPT_ARGS]; 35092a174df0SBart Van Assche unsigned long long ull; 3510bcef5b72SBart Van Assche bool has_port; 3511aef9ec39SRoland Dreier int opt_mask = 0; 3512aef9ec39SRoland Dreier int token; 3513aef9ec39SRoland Dreier int ret = -EINVAL; 3514aef9ec39SRoland Dreier int i; 3515aef9ec39SRoland Dreier 3516aef9ec39SRoland Dreier options = kstrdup(buf, GFP_KERNEL); 3517aef9ec39SRoland Dreier if (!options) 3518aef9ec39SRoland Dreier return -ENOMEM; 3519aef9ec39SRoland Dreier 3520aef9ec39SRoland Dreier sep_opt = options; 35217dcf9c19SSagi Grimberg while ((p = strsep(&sep_opt, ",\n")) != NULL) { 3522aef9ec39SRoland Dreier if (!*p) 3523aef9ec39SRoland Dreier continue; 3524aef9ec39SRoland Dreier 3525aef9ec39SRoland Dreier token = match_token(p, srp_opt_tokens, args); 3526aef9ec39SRoland Dreier opt_mask |= token; 3527aef9ec39SRoland Dreier 3528aef9ec39SRoland Dreier switch (token) { 3529aef9ec39SRoland Dreier case SRP_OPT_ID_EXT: 3530aef9ec39SRoland Dreier p = match_strdup(args); 3531a20f3a6dSIshai Rabinovitz if (!p) { 3532a20f3a6dSIshai Rabinovitz ret = -ENOMEM; 3533a20f3a6dSIshai Rabinovitz goto out; 3534a20f3a6dSIshai Rabinovitz } 35352a174df0SBart Van Assche ret = kstrtoull(p, 16, &ull); 35362a174df0SBart Van Assche if (ret) { 35372a174df0SBart Van Assche pr_warn("invalid id_ext parameter '%s'\n", p); 35382a174df0SBart Van Assche kfree(p); 35392a174df0SBart Van Assche goto out; 35402a174df0SBart Van Assche } 35412a174df0SBart Van Assche target->id_ext = cpu_to_be64(ull); 3542aef9ec39SRoland Dreier kfree(p); 3543aef9ec39SRoland Dreier break; 3544aef9ec39SRoland Dreier 3545aef9ec39SRoland Dreier case SRP_OPT_IOC_GUID: 3546aef9ec39SRoland Dreier p = match_strdup(args); 3547a20f3a6dSIshai Rabinovitz if (!p) { 3548a20f3a6dSIshai Rabinovitz ret = -ENOMEM; 3549a20f3a6dSIshai Rabinovitz goto out; 3550a20f3a6dSIshai Rabinovitz } 35512a174df0SBart Van Assche ret = kstrtoull(p, 16, &ull); 35522a174df0SBart Van Assche if (ret) { 35532a174df0SBart Van Assche pr_warn("invalid ioc_guid parameter '%s'\n", p); 35542a174df0SBart Van Assche kfree(p); 35552a174df0SBart Van Assche goto out; 35562a174df0SBart Van Assche } 35572a174df0SBart Van Assche target->ioc_guid = cpu_to_be64(ull); 3558aef9ec39SRoland Dreier kfree(p); 3559aef9ec39SRoland Dreier break; 3560aef9ec39SRoland Dreier 3561aef9ec39SRoland Dreier case SRP_OPT_DGID: 3562aef9ec39SRoland Dreier p = match_strdup(args); 3563a20f3a6dSIshai Rabinovitz if (!p) { 3564a20f3a6dSIshai Rabinovitz ret = -ENOMEM; 3565a20f3a6dSIshai Rabinovitz goto out; 3566a20f3a6dSIshai Rabinovitz } 3567aef9ec39SRoland Dreier if (strlen(p) != 32) { 3568e0bda7d8SBart Van Assche pr_warn("bad dest GID parameter '%s'\n", p); 3569ce1823f0SRoland Dreier kfree(p); 3570aef9ec39SRoland Dreier goto out; 3571aef9ec39SRoland Dreier } 3572aef9ec39SRoland Dreier 357319f31343SBart Van Assche ret = hex2bin(target->ib_cm.orig_dgid.raw, p, 16); 3574747fe000SBart Van Assche kfree(p); 3575e711f968SAndy Shevchenko if (ret < 0) 3576747fe000SBart Van Assche goto out; 3577aef9ec39SRoland Dreier break; 3578aef9ec39SRoland Dreier 3579aef9ec39SRoland Dreier case SRP_OPT_PKEY: 3580aef9ec39SRoland Dreier if (match_hex(args, &token)) { 3581e0bda7d8SBart Van Assche pr_warn("bad P_Key parameter '%s'\n", p); 3582aef9ec39SRoland Dreier goto out; 3583aef9ec39SRoland Dreier } 358419f31343SBart Van Assche target->ib_cm.pkey = cpu_to_be16(token); 3585aef9ec39SRoland Dreier break; 3586aef9ec39SRoland Dreier 3587aef9ec39SRoland Dreier case SRP_OPT_SERVICE_ID: 3588aef9ec39SRoland Dreier p = match_strdup(args); 3589a20f3a6dSIshai Rabinovitz if (!p) { 3590a20f3a6dSIshai Rabinovitz ret = -ENOMEM; 3591a20f3a6dSIshai Rabinovitz goto out; 3592a20f3a6dSIshai Rabinovitz } 35932a174df0SBart Van Assche ret = kstrtoull(p, 16, &ull); 35942a174df0SBart Van Assche if (ret) { 35952a174df0SBart Van Assche pr_warn("bad service_id parameter '%s'\n", p); 35962a174df0SBart Van Assche kfree(p); 35972a174df0SBart Van Assche goto out; 35982a174df0SBart Van Assche } 359919f31343SBart Van Assche target->ib_cm.service_id = cpu_to_be64(ull); 360019f31343SBart Van Assche kfree(p); 360119f31343SBart Van Assche break; 360219f31343SBart Van Assche 360319f31343SBart Van Assche case SRP_OPT_IP_SRC: 360419f31343SBart Van Assche p = match_strdup(args); 360519f31343SBart Van Assche if (!p) { 360619f31343SBart Van Assche ret = -ENOMEM; 360719f31343SBart Van Assche goto out; 360819f31343SBart Van Assche } 3609bcef5b72SBart Van Assche ret = srp_parse_in(net, &target->rdma_cm.src.ss, p, 3610bcef5b72SBart Van Assche NULL); 361119f31343SBart Van Assche if (ret < 0) { 361219f31343SBart Van Assche pr_warn("bad source parameter '%s'\n", p); 361319f31343SBart Van Assche kfree(p); 361419f31343SBart Van Assche goto out; 361519f31343SBart Van Assche } 361619f31343SBart Van Assche target->rdma_cm.src_specified = true; 361719f31343SBart Van Assche kfree(p); 361819f31343SBart Van Assche break; 361919f31343SBart Van Assche 362019f31343SBart Van Assche case SRP_OPT_IP_DEST: 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 } 3626bcef5b72SBart Van Assche ret = srp_parse_in(net, &target->rdma_cm.dst.ss, p, 3627bcef5b72SBart Van Assche &has_port); 3628bcef5b72SBart Van Assche if (!has_port) 3629bcef5b72SBart Van Assche ret = -EINVAL; 363019f31343SBart Van Assche if (ret < 0) { 363119f31343SBart Van Assche pr_warn("bad dest parameter '%s'\n", p); 363219f31343SBart Van Assche kfree(p); 363319f31343SBart Van Assche goto out; 363419f31343SBart Van Assche } 363519f31343SBart Van Assche target->using_rdma_cm = true; 3636aef9ec39SRoland Dreier kfree(p); 3637aef9ec39SRoland Dreier break; 3638aef9ec39SRoland Dreier 3639aef9ec39SRoland Dreier case SRP_OPT_MAX_SECT: 3640aef9ec39SRoland Dreier if (match_int(args, &token)) { 3641e0bda7d8SBart Van Assche pr_warn("bad max sect parameter '%s'\n", p); 3642aef9ec39SRoland Dreier goto out; 3643aef9ec39SRoland Dreier } 3644aef9ec39SRoland Dreier target->scsi_host->max_sectors = token; 3645aef9ec39SRoland Dreier break; 3646aef9ec39SRoland Dreier 36474d73f95fSBart Van Assche case SRP_OPT_QUEUE_SIZE: 36484d73f95fSBart Van Assche if (match_int(args, &token) || token < 1) { 36494d73f95fSBart Van Assche pr_warn("bad queue_size parameter '%s'\n", p); 36504d73f95fSBart Van Assche goto out; 36514d73f95fSBart Van Assche } 36524d73f95fSBart Van Assche target->scsi_host->can_queue = token; 36534d73f95fSBart Van Assche target->queue_size = token + SRP_RSP_SQ_SIZE + 36544d73f95fSBart Van Assche SRP_TSK_MGMT_SQ_SIZE; 36554d73f95fSBart Van Assche if (!(opt_mask & SRP_OPT_MAX_CMD_PER_LUN)) 36564d73f95fSBart Van Assche target->scsi_host->cmd_per_lun = token; 36574d73f95fSBart Van Assche break; 36584d73f95fSBart Van Assche 365952fb2b50SVu Pham case SRP_OPT_MAX_CMD_PER_LUN: 36604d73f95fSBart Van Assche if (match_int(args, &token) || token < 1) { 3661e0bda7d8SBart Van Assche pr_warn("bad max cmd_per_lun parameter '%s'\n", 3662e0bda7d8SBart Van Assche p); 366352fb2b50SVu Pham goto out; 366452fb2b50SVu Pham } 36654d73f95fSBart Van Assche target->scsi_host->cmd_per_lun = token; 366652fb2b50SVu Pham break; 366752fb2b50SVu Pham 3668b0780ee5SBart Van Assche case SRP_OPT_TARGET_CAN_QUEUE: 3669b0780ee5SBart Van Assche if (match_int(args, &token) || token < 1) { 3670b0780ee5SBart Van Assche pr_warn("bad max target_can_queue parameter '%s'\n", 3671b0780ee5SBart Van Assche p); 3672b0780ee5SBart Van Assche goto out; 3673b0780ee5SBart Van Assche } 3674b0780ee5SBart Van Assche target->target_can_queue = token; 3675b0780ee5SBart Van Assche break; 3676b0780ee5SBart Van Assche 36770c0450dbSRamachandra K case SRP_OPT_IO_CLASS: 36780c0450dbSRamachandra K if (match_hex(args, &token)) { 3679e0bda7d8SBart Van Assche pr_warn("bad IO class parameter '%s'\n", p); 36800c0450dbSRamachandra K goto out; 36810c0450dbSRamachandra K } 36820c0450dbSRamachandra K if (token != SRP_REV10_IB_IO_CLASS && 36830c0450dbSRamachandra K token != SRP_REV16A_IB_IO_CLASS) { 3684e0bda7d8SBart Van Assche pr_warn("unknown IO class parameter value %x specified (use %x or %x).\n", 3685e0bda7d8SBart Van Assche token, SRP_REV10_IB_IO_CLASS, 3686e0bda7d8SBart Van Assche SRP_REV16A_IB_IO_CLASS); 36870c0450dbSRamachandra K goto out; 36880c0450dbSRamachandra K } 36890c0450dbSRamachandra K target->io_class = token; 36900c0450dbSRamachandra K break; 36910c0450dbSRamachandra K 369201cb9bcbSIshai Rabinovitz case SRP_OPT_INITIATOR_EXT: 369301cb9bcbSIshai Rabinovitz p = match_strdup(args); 3694a20f3a6dSIshai Rabinovitz if (!p) { 3695a20f3a6dSIshai Rabinovitz ret = -ENOMEM; 3696a20f3a6dSIshai Rabinovitz goto out; 3697a20f3a6dSIshai Rabinovitz } 36982a174df0SBart Van Assche ret = kstrtoull(p, 16, &ull); 36992a174df0SBart Van Assche if (ret) { 37002a174df0SBart Van Assche pr_warn("bad initiator_ext value '%s'\n", p); 37012a174df0SBart Van Assche kfree(p); 37022a174df0SBart Van Assche goto out; 37032a174df0SBart Van Assche } 37042a174df0SBart Van Assche target->initiator_ext = cpu_to_be64(ull); 370501cb9bcbSIshai Rabinovitz kfree(p); 370601cb9bcbSIshai Rabinovitz break; 370701cb9bcbSIshai Rabinovitz 370849248644SDavid Dillow case SRP_OPT_CMD_SG_ENTRIES: 370949248644SDavid Dillow if (match_int(args, &token) || token < 1 || token > 255) { 3710e0bda7d8SBart Van Assche pr_warn("bad max cmd_sg_entries parameter '%s'\n", 3711e0bda7d8SBart Van Assche p); 371249248644SDavid Dillow goto out; 371349248644SDavid Dillow } 371449248644SDavid Dillow target->cmd_sg_cnt = token; 371549248644SDavid Dillow break; 371649248644SDavid Dillow 3717c07d424dSDavid Dillow case SRP_OPT_ALLOW_EXT_SG: 3718c07d424dSDavid Dillow if (match_int(args, &token)) { 3719e0bda7d8SBart Van Assche pr_warn("bad allow_ext_sg parameter '%s'\n", p); 3720c07d424dSDavid Dillow goto out; 3721c07d424dSDavid Dillow } 3722c07d424dSDavid Dillow target->allow_ext_sg = !!token; 3723c07d424dSDavid Dillow break; 3724c07d424dSDavid Dillow 3725c07d424dSDavid Dillow case SRP_OPT_SG_TABLESIZE: 3726c07d424dSDavid Dillow if (match_int(args, &token) || token < 1 || 372765e8617fSMing Lin token > SG_MAX_SEGMENTS) { 3728e0bda7d8SBart Van Assche pr_warn("bad max sg_tablesize parameter '%s'\n", 3729e0bda7d8SBart Van Assche p); 3730c07d424dSDavid Dillow goto out; 3731c07d424dSDavid Dillow } 3732c07d424dSDavid Dillow target->sg_tablesize = token; 3733c07d424dSDavid Dillow break; 3734c07d424dSDavid Dillow 37354b5e5f41SBart Van Assche case SRP_OPT_COMP_VECTOR: 37364b5e5f41SBart Van Assche if (match_int(args, &token) || token < 0) { 37374b5e5f41SBart Van Assche pr_warn("bad comp_vector parameter '%s'\n", p); 37384b5e5f41SBart Van Assche goto out; 37394b5e5f41SBart Van Assche } 37404b5e5f41SBart Van Assche target->comp_vector = token; 37414b5e5f41SBart Van Assche break; 37424b5e5f41SBart Van Assche 37437bb312e4SVu Pham case SRP_OPT_TL_RETRY_COUNT: 37447bb312e4SVu Pham if (match_int(args, &token) || token < 2 || token > 7) { 37457bb312e4SVu Pham pr_warn("bad tl_retry_count parameter '%s' (must be a number between 2 and 7)\n", 37467bb312e4SVu Pham p); 37477bb312e4SVu Pham goto out; 37487bb312e4SVu Pham } 37497bb312e4SVu Pham target->tl_retry_count = token; 37507bb312e4SVu Pham break; 37517bb312e4SVu Pham 3752547ed331SHonggang Li case SRP_OPT_MAX_IT_IU_SIZE: 3753547ed331SHonggang Li if (match_int(args, &token) || token < 0) { 3754547ed331SHonggang Li pr_warn("bad maximum initiator to target IU size '%s'\n", p); 3755547ed331SHonggang Li goto out; 3756547ed331SHonggang Li } 3757547ed331SHonggang Li target->max_it_iu_size = token; 3758547ed331SHonggang Li break; 3759547ed331SHonggang Li 3760aef9ec39SRoland Dreier default: 3761e0bda7d8SBart Van Assche pr_warn("unknown parameter or missing value '%s' in target creation request\n", 3762e0bda7d8SBart Van Assche p); 3763aef9ec39SRoland Dreier goto out; 3764aef9ec39SRoland Dreier } 3765aef9ec39SRoland Dreier } 3766aef9ec39SRoland Dreier 376719f31343SBart Van Assche for (i = 0; i < ARRAY_SIZE(srp_opt_mandatory); i++) { 376819f31343SBart Van Assche if ((opt_mask & srp_opt_mandatory[i]) == srp_opt_mandatory[i]) { 3769aef9ec39SRoland Dreier ret = 0; 377019f31343SBart Van Assche break; 377119f31343SBart Van Assche } 377219f31343SBart Van Assche } 377319f31343SBart Van Assche if (ret) 377419f31343SBart Van Assche pr_warn("target creation request is missing one or more parameters\n"); 3775aef9ec39SRoland Dreier 37764d73f95fSBart Van Assche if (target->scsi_host->cmd_per_lun > target->scsi_host->can_queue 37774d73f95fSBart Van Assche && (opt_mask & SRP_OPT_MAX_CMD_PER_LUN)) 37784d73f95fSBart Van Assche pr_warn("cmd_per_lun = %d > queue_size = %d\n", 37794d73f95fSBart Van Assche target->scsi_host->cmd_per_lun, 37804d73f95fSBart Van Assche target->scsi_host->can_queue); 37814d73f95fSBart Van Assche 3782aef9ec39SRoland Dreier out: 3783aef9ec39SRoland Dreier kfree(options); 3784aef9ec39SRoland Dreier return ret; 3785aef9ec39SRoland Dreier } 3786aef9ec39SRoland Dreier 3787ee959b00STony Jones static ssize_t srp_create_target(struct device *dev, 3788ee959b00STony Jones struct device_attribute *attr, 3789aef9ec39SRoland Dreier const char *buf, size_t count) 3790aef9ec39SRoland Dreier { 3791aef9ec39SRoland Dreier struct srp_host *host = 3792ee959b00STony Jones container_of(dev, struct srp_host, dev); 3793aef9ec39SRoland Dreier struct Scsi_Host *target_host; 3794aef9ec39SRoland Dreier struct srp_target_port *target; 3795509c07bcSBart Van Assche struct srp_rdma_ch *ch; 3796d1b4289eSBart Van Assche struct srp_device *srp_dev = host->srp_dev; 3797d1b4289eSBart Van Assche struct ib_device *ibdev = srp_dev->dev; 3798d92c0da7SBart Van Assche int ret, node_idx, node, cpu, i; 3799509c5f33SBart Van Assche unsigned int max_sectors_per_mr, mr_per_cmd = 0; 3800d92c0da7SBart Van Assche bool multich = false; 3801513d5647SBart Van Assche uint32_t max_iu_len; 3802aef9ec39SRoland Dreier 3803aef9ec39SRoland Dreier target_host = scsi_host_alloc(&srp_template, 3804aef9ec39SRoland Dreier sizeof (struct srp_target_port)); 3805aef9ec39SRoland Dreier if (!target_host) 3806aef9ec39SRoland Dreier return -ENOMEM; 3807aef9ec39SRoland Dreier 38083236822bSFUJITA Tomonori target_host->transportt = ib_srp_transport_template; 3809fd1b6c4aSBart Van Assche target_host->max_channel = 0; 3810fd1b6c4aSBart Van Assche target_host->max_id = 1; 3811985aa495SBart Van Assche target_host->max_lun = -1LL; 38123c8edf0eSArne Redlich target_host->max_cmd_len = sizeof ((struct srp_cmd *) (void *) 0L)->cdb; 38130b5cb330SBart Van Assche target_host->max_segment_size = ib_dma_max_seg_size(ibdev); 38145f068992SRoland Dreier 38158c175d31SChristoph Hellwig if (!(ibdev->attrs.device_cap_flags & IB_DEVICE_SG_GAPS_REG)) 38168c175d31SChristoph Hellwig target_host->virt_boundary_mask = ~srp_dev->mr_page_mask; 38178c175d31SChristoph Hellwig 3818aef9ec39SRoland Dreier target = host_to_target(target_host); 3819aef9ec39SRoland Dreier 382019f31343SBart Van Assche target->net = kobj_ns_grab_current(KOBJ_NS_TYPE_NET); 38210c0450dbSRamachandra K target->io_class = SRP_REV16A_IB_IO_CLASS; 3822aef9ec39SRoland Dreier target->scsi_host = target_host; 3823aef9ec39SRoland Dreier target->srp_host = host; 3824e6bf5f48SJason Gunthorpe target->lkey = host->srp_dev->pd->local_dma_lkey; 3825cee687b6SBart Van Assche target->global_rkey = host->srp_dev->global_rkey; 382649248644SDavid Dillow target->cmd_sg_cnt = cmd_sg_entries; 3827c07d424dSDavid Dillow target->sg_tablesize = indirect_sg_entries ? : cmd_sg_entries; 3828c07d424dSDavid Dillow target->allow_ext_sg = allow_ext_sg; 38297bb312e4SVu Pham target->tl_retry_count = 7; 38304d73f95fSBart Van Assche target->queue_size = SRP_DEFAULT_QUEUE_SIZE; 3831aef9ec39SRoland Dreier 383234aa654eSBart Van Assche /* 383334aa654eSBart Van Assche * Avoid that the SCSI host can be removed by srp_remove_target() 383434aa654eSBart Van Assche * before this function returns. 383534aa654eSBart Van Assche */ 383634aa654eSBart Van Assche scsi_host_get(target->scsi_host); 383734aa654eSBart Van Assche 38384fa354c9SBart Van Assche ret = mutex_lock_interruptible(&host->add_target_mutex); 38394fa354c9SBart Van Assche if (ret < 0) 38404fa354c9SBart Van Assche goto put; 38412d7091bcSBart Van Assche 384219f31343SBart Van Assche ret = srp_parse_options(target->net, buf, target); 3843aef9ec39SRoland Dreier if (ret) 3844fb49c8bbSBart Van Assche goto out; 3845aef9ec39SRoland Dreier 38464d73f95fSBart Van Assche target->req_ring_size = target->queue_size - SRP_TSK_MGMT_SQ_SIZE; 38474d73f95fSBart Van Assche 384896fc248aSBart Van Assche if (!srp_conn_unique(target->srp_host, target)) { 384919f31343SBart Van Assche if (target->using_rdma_cm) { 385019f31343SBart Van Assche shost_printk(KERN_INFO, target->scsi_host, 38517da09af9SBart Van Assche PFX "Already connected to target port with id_ext=%016llx;ioc_guid=%016llx;dest=%pIS\n", 385219f31343SBart Van Assche be64_to_cpu(target->id_ext), 385319f31343SBart Van Assche be64_to_cpu(target->ioc_guid), 38547da09af9SBart Van Assche &target->rdma_cm.dst); 385519f31343SBart Van Assche } else { 385696fc248aSBart Van Assche shost_printk(KERN_INFO, target->scsi_host, 385796fc248aSBart Van Assche PFX "Already connected to target port with id_ext=%016llx;ioc_guid=%016llx;initiator_ext=%016llx\n", 385896fc248aSBart Van Assche be64_to_cpu(target->id_ext), 385996fc248aSBart Van Assche be64_to_cpu(target->ioc_guid), 386096fc248aSBart Van Assche be64_to_cpu(target->initiator_ext)); 386119f31343SBart Van Assche } 386296fc248aSBart Van Assche ret = -EEXIST; 3863fb49c8bbSBart Van Assche goto out; 386496fc248aSBart Van Assche } 386596fc248aSBart Van Assche 38665cfb1782SBart Van Assche if (!srp_dev->has_fmr && !srp_dev->has_fr && !target->allow_ext_sg && 3867c07d424dSDavid Dillow target->cmd_sg_cnt < target->sg_tablesize) { 38685cfb1782SBart Van Assche pr_warn("No MR pool and no external indirect descriptors, limiting sg_tablesize to cmd_sg_cnt\n"); 3869c07d424dSDavid Dillow target->sg_tablesize = target->cmd_sg_cnt; 3870c07d424dSDavid Dillow } 3871c07d424dSDavid Dillow 3872509c5f33SBart Van Assche if (srp_dev->use_fast_reg || srp_dev->use_fmr) { 3873fbd36818SSergey Gorenko bool gaps_reg = (ibdev->attrs.device_cap_flags & 3874fbd36818SSergey Gorenko IB_DEVICE_SG_GAPS_REG); 3875fbd36818SSergey Gorenko 3876509c5f33SBart Van Assche max_sectors_per_mr = srp_dev->max_pages_per_mr << 3877509c5f33SBart Van Assche (ilog2(srp_dev->mr_page_size) - 9); 3878fbd36818SSergey Gorenko if (!gaps_reg) { 3879fbd36818SSergey Gorenko /* 3880fbd36818SSergey Gorenko * FR and FMR can only map one HCA page per entry. If 3881fbd36818SSergey Gorenko * the start address is not aligned on a HCA page 3882fbd36818SSergey Gorenko * boundary two entries will be used for the head and 3883fbd36818SSergey Gorenko * the tail although these two entries combined 3884fbd36818SSergey Gorenko * contain at most one HCA page of data. Hence the "+ 3885fbd36818SSergey Gorenko * 1" in the calculation below. 3886fbd36818SSergey Gorenko * 3887fbd36818SSergey Gorenko * The indirect data buffer descriptor is contiguous 3888fbd36818SSergey Gorenko * so the memory for that buffer will only be 3889fbd36818SSergey Gorenko * registered if register_always is true. Hence add 3890fbd36818SSergey Gorenko * one to mr_per_cmd if register_always has been set. 3891fbd36818SSergey Gorenko */ 3892509c5f33SBart Van Assche mr_per_cmd = register_always + 3893509c5f33SBart Van Assche (target->scsi_host->max_sectors + 1 + 3894509c5f33SBart Van Assche max_sectors_per_mr - 1) / max_sectors_per_mr; 3895fbd36818SSergey Gorenko } else { 3896fbd36818SSergey Gorenko mr_per_cmd = register_always + 3897fbd36818SSergey Gorenko (target->sg_tablesize + 3898fbd36818SSergey Gorenko srp_dev->max_pages_per_mr - 1) / 3899fbd36818SSergey Gorenko srp_dev->max_pages_per_mr; 3900fbd36818SSergey Gorenko } 3901509c5f33SBart 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", 3902fbd36818SSergey Gorenko target->scsi_host->max_sectors, srp_dev->max_pages_per_mr, srp_dev->mr_page_size, 3903509c5f33SBart Van Assche max_sectors_per_mr, mr_per_cmd); 3904509c5f33SBart Van Assche } 3905509c5f33SBart Van Assche 3906c07d424dSDavid Dillow target_host->sg_tablesize = target->sg_tablesize; 3907509c5f33SBart Van Assche target->mr_pool_size = target->scsi_host->can_queue * mr_per_cmd; 3908509c5f33SBart Van Assche target->mr_per_cmd = mr_per_cmd; 3909c07d424dSDavid Dillow target->indirect_size = target->sg_tablesize * 3910c07d424dSDavid Dillow sizeof (struct srp_direct_buf); 3911*b2e872f4SHonggang Li max_iu_len = srp_max_it_iu_len(target->cmd_sg_cnt, 3912*b2e872f4SHonggang Li srp_use_imm_data, 3913*b2e872f4SHonggang Li target->max_it_iu_size); 391449248644SDavid Dillow 3915c1120f89SBart Van Assche INIT_WORK(&target->tl_err_work, srp_tl_err_work); 3916ef6c49d8SBart Van Assche INIT_WORK(&target->remove_work, srp_remove_work); 39178f26c9ffSDavid Dillow spin_lock_init(&target->lock); 39181dfce294SParav Pandit ret = rdma_query_gid(ibdev, host->port, 0, &target->sgid); 39192088ca66SSagi Grimberg if (ret) 3920fb49c8bbSBart Van Assche goto out; 3921d92c0da7SBart Van Assche 3922d92c0da7SBart Van Assche ret = -ENOMEM; 3923d92c0da7SBart Van Assche target->ch_count = max_t(unsigned, num_online_nodes(), 3924d92c0da7SBart Van Assche min(ch_count ? : 3925d92c0da7SBart Van Assche min(4 * num_online_nodes(), 3926d92c0da7SBart Van Assche ibdev->num_comp_vectors), 3927d92c0da7SBart Van Assche num_online_cpus())); 3928d92c0da7SBart Van Assche target->ch = kcalloc(target->ch_count, sizeof(*target->ch), 3929d92c0da7SBart Van Assche GFP_KERNEL); 3930d92c0da7SBart Van Assche if (!target->ch) 3931fb49c8bbSBart Van Assche goto out; 3932d92c0da7SBart Van Assche 3933d92c0da7SBart Van Assche node_idx = 0; 3934d92c0da7SBart Van Assche for_each_online_node(node) { 3935d92c0da7SBart Van Assche const int ch_start = (node_idx * target->ch_count / 3936d92c0da7SBart Van Assche num_online_nodes()); 3937d92c0da7SBart Van Assche const int ch_end = ((node_idx + 1) * target->ch_count / 3938d92c0da7SBart Van Assche num_online_nodes()); 39393a148896SBart Van Assche const int cv_start = node_idx * ibdev->num_comp_vectors / 39403a148896SBart Van Assche num_online_nodes(); 39413a148896SBart Van Assche const int cv_end = (node_idx + 1) * ibdev->num_comp_vectors / 39423a148896SBart Van Assche num_online_nodes(); 3943d92c0da7SBart Van Assche int cpu_idx = 0; 3944d92c0da7SBart Van Assche 3945d92c0da7SBart Van Assche for_each_online_cpu(cpu) { 3946d92c0da7SBart Van Assche if (cpu_to_node(cpu) != node) 3947d92c0da7SBart Van Assche continue; 3948d92c0da7SBart Van Assche if (ch_start + cpu_idx >= ch_end) 3949d92c0da7SBart Van Assche continue; 3950d92c0da7SBart Van Assche ch = &target->ch[ch_start + cpu_idx]; 3951d92c0da7SBart Van Assche ch->target = target; 3952d92c0da7SBart Van Assche ch->comp_vector = cv_start == cv_end ? cv_start : 3953d92c0da7SBart Van Assche cv_start + cpu_idx % (cv_end - cv_start); 3954d92c0da7SBart Van Assche spin_lock_init(&ch->lock); 3955d92c0da7SBart Van Assche INIT_LIST_HEAD(&ch->free_tx); 3956d92c0da7SBart Van Assche ret = srp_new_cm_id(ch); 3957d92c0da7SBart Van Assche if (ret) 3958d92c0da7SBart Van Assche goto err_disconnect; 3959aef9ec39SRoland Dreier 3960509c07bcSBart Van Assche ret = srp_create_ch_ib(ch); 3961aef9ec39SRoland Dreier if (ret) 3962d92c0da7SBart Van Assche goto err_disconnect; 3963aef9ec39SRoland Dreier 3964d92c0da7SBart Van Assche ret = srp_alloc_req_data(ch); 39659fe4bcf4SDavid Dillow if (ret) 3966d92c0da7SBart Van Assche goto err_disconnect; 3967aef9ec39SRoland Dreier 3968513d5647SBart Van Assche ret = srp_connect_ch(ch, max_iu_len, multich); 3969aef9ec39SRoland Dreier if (ret) { 397019f31343SBart Van Assche char dst[64]; 397119f31343SBart Van Assche 397219f31343SBart Van Assche if (target->using_rdma_cm) 39737da09af9SBart Van Assche snprintf(dst, sizeof(dst), "%pIS", 39747da09af9SBart Van Assche &target->rdma_cm.dst); 397519f31343SBart Van Assche else 397619f31343SBart Van Assche snprintf(dst, sizeof(dst), "%pI6", 397719f31343SBart Van Assche target->ib_cm.orig_dgid.raw); 39787aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 397919f31343SBart Van Assche PFX "Connection %d/%d to %s failed\n", 3980d92c0da7SBart Van Assche ch_start + cpu_idx, 398119f31343SBart Van Assche target->ch_count, dst); 3982d92c0da7SBart Van Assche if (node_idx == 0 && cpu_idx == 0) { 3983b02c1536SBart Van Assche goto free_ch; 3984d92c0da7SBart Van Assche } else { 3985d92c0da7SBart Van Assche srp_free_ch_ib(target, ch); 3986d92c0da7SBart Van Assche srp_free_req_data(target, ch); 3987d92c0da7SBart Van Assche target->ch_count = ch - target->ch; 3988c257ea6fSBart Van Assche goto connected; 3989aef9ec39SRoland Dreier } 3990d92c0da7SBart Van Assche } 3991d92c0da7SBart Van Assche 3992d92c0da7SBart Van Assche multich = true; 3993d92c0da7SBart Van Assche cpu_idx++; 3994d92c0da7SBart Van Assche } 3995d92c0da7SBart Van Assche node_idx++; 3996d92c0da7SBart Van Assche } 3997d92c0da7SBart Van Assche 3998c257ea6fSBart Van Assche connected: 3999d92c0da7SBart Van Assche target->scsi_host->nr_hw_queues = target->ch_count; 4000aef9ec39SRoland Dreier 4001aef9ec39SRoland Dreier ret = srp_add_target(host, target); 4002aef9ec39SRoland Dreier if (ret) 4003aef9ec39SRoland Dreier goto err_disconnect; 4004aef9ec39SRoland Dreier 400534aa654eSBart Van Assche if (target->state != SRP_TARGET_REMOVED) { 400619f31343SBart Van Assche if (target->using_rdma_cm) { 400719f31343SBart Van Assche shost_printk(KERN_DEBUG, target->scsi_host, PFX 40087da09af9SBart Van Assche "new target: id_ext %016llx ioc_guid %016llx sgid %pI6 dest %pIS\n", 400919f31343SBart Van Assche be64_to_cpu(target->id_ext), 401019f31343SBart Van Assche be64_to_cpu(target->ioc_guid), 40117da09af9SBart Van Assche target->sgid.raw, &target->rdma_cm.dst); 401219f31343SBart Van Assche } else { 4013e7ffde01SBart Van Assche shost_printk(KERN_DEBUG, target->scsi_host, PFX 4014e7ffde01SBart Van Assche "new target: id_ext %016llx ioc_guid %016llx pkey %04x service_id %016llx sgid %pI6 dgid %pI6\n", 4015e7ffde01SBart Van Assche be64_to_cpu(target->id_ext), 4016e7ffde01SBart Van Assche be64_to_cpu(target->ioc_guid), 401719f31343SBart Van Assche be16_to_cpu(target->ib_cm.pkey), 401819f31343SBart Van Assche be64_to_cpu(target->ib_cm.service_id), 401919f31343SBart Van Assche target->sgid.raw, 402019f31343SBart Van Assche target->ib_cm.orig_dgid.raw); 402119f31343SBart Van Assche } 402234aa654eSBart Van Assche } 4023e7ffde01SBart Van Assche 40242d7091bcSBart Van Assche ret = count; 40252d7091bcSBart Van Assche 40262d7091bcSBart Van Assche out: 40272d7091bcSBart Van Assche mutex_unlock(&host->add_target_mutex); 402834aa654eSBart Van Assche 40294fa354c9SBart Van Assche put: 403034aa654eSBart Van Assche scsi_host_put(target->scsi_host); 403119f31343SBart Van Assche if (ret < 0) { 403219f31343SBart Van Assche /* 403319f31343SBart Van Assche * If a call to srp_remove_target() has not been scheduled, 403419f31343SBart Van Assche * drop the network namespace reference now that was obtained 403519f31343SBart Van Assche * earlier in this function. 403619f31343SBart Van Assche */ 403719f31343SBart Van Assche if (target->state != SRP_TARGET_REMOVED) 403819f31343SBart Van Assche kobj_ns_drop(KOBJ_NS_TYPE_NET, target->net); 4039bc44bd1dSBart Van Assche scsi_host_put(target->scsi_host); 404019f31343SBart Van Assche } 404134aa654eSBart Van Assche 40422d7091bcSBart Van Assche return ret; 4043aef9ec39SRoland Dreier 4044aef9ec39SRoland Dreier err_disconnect: 4045aef9ec39SRoland Dreier srp_disconnect_target(target); 4046aef9ec39SRoland Dreier 4047b02c1536SBart Van Assche free_ch: 4048d92c0da7SBart Van Assche for (i = 0; i < target->ch_count; i++) { 4049d92c0da7SBart Van Assche ch = &target->ch[i]; 4050509c07bcSBart Van Assche srp_free_ch_ib(target, ch); 4051509c07bcSBart Van Assche srp_free_req_data(target, ch); 4052d92c0da7SBart Van Assche } 4053d92c0da7SBart Van Assche 4054d92c0da7SBart Van Assche kfree(target->ch); 40552d7091bcSBart Van Assche goto out; 4056aef9ec39SRoland Dreier } 4057aef9ec39SRoland Dreier 4058ee959b00STony Jones static DEVICE_ATTR(add_target, S_IWUSR, NULL, srp_create_target); 4059aef9ec39SRoland Dreier 4060ee959b00STony Jones static ssize_t show_ibdev(struct device *dev, struct device_attribute *attr, 4061ee959b00STony Jones char *buf) 4062aef9ec39SRoland Dreier { 4063ee959b00STony Jones struct srp_host *host = container_of(dev, struct srp_host, dev); 4064aef9ec39SRoland Dreier 40656c854111SJason Gunthorpe return sprintf(buf, "%s\n", dev_name(&host->srp_dev->dev->dev)); 4066aef9ec39SRoland Dreier } 4067aef9ec39SRoland Dreier 4068ee959b00STony Jones static DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL); 4069aef9ec39SRoland Dreier 4070ee959b00STony Jones static ssize_t show_port(struct device *dev, struct device_attribute *attr, 4071ee959b00STony Jones char *buf) 4072aef9ec39SRoland Dreier { 4073ee959b00STony Jones struct srp_host *host = container_of(dev, struct srp_host, dev); 4074aef9ec39SRoland Dreier 4075aef9ec39SRoland Dreier return sprintf(buf, "%d\n", host->port); 4076aef9ec39SRoland Dreier } 4077aef9ec39SRoland Dreier 4078ee959b00STony Jones static DEVICE_ATTR(port, S_IRUGO, show_port, NULL); 4079aef9ec39SRoland Dreier 4080f5358a17SRoland Dreier static struct srp_host *srp_add_port(struct srp_device *device, u8 port) 4081aef9ec39SRoland Dreier { 4082aef9ec39SRoland Dreier struct srp_host *host; 4083aef9ec39SRoland Dreier 4084aef9ec39SRoland Dreier host = kzalloc(sizeof *host, GFP_KERNEL); 4085aef9ec39SRoland Dreier if (!host) 4086aef9ec39SRoland Dreier return NULL; 4087aef9ec39SRoland Dreier 4088aef9ec39SRoland Dreier INIT_LIST_HEAD(&host->target_list); 4089b3589fd4SMatthew Wilcox spin_lock_init(&host->target_lock); 4090aef9ec39SRoland Dreier init_completion(&host->released); 40912d7091bcSBart Van Assche mutex_init(&host->add_target_mutex); 409205321937SGreg Kroah-Hartman host->srp_dev = device; 4093aef9ec39SRoland Dreier host->port = port; 4094aef9ec39SRoland Dreier 4095ee959b00STony Jones host->dev.class = &srp_class; 4096dee2b82aSBart Van Assche host->dev.parent = device->dev->dev.parent; 40976c854111SJason Gunthorpe dev_set_name(&host->dev, "srp-%s-%d", dev_name(&device->dev->dev), 40986c854111SJason Gunthorpe port); 4099aef9ec39SRoland Dreier 4100ee959b00STony Jones if (device_register(&host->dev)) 4101f5358a17SRoland Dreier goto free_host; 4102ee959b00STony Jones if (device_create_file(&host->dev, &dev_attr_add_target)) 4103aef9ec39SRoland Dreier goto err_class; 4104ee959b00STony Jones if (device_create_file(&host->dev, &dev_attr_ibdev)) 4105aef9ec39SRoland Dreier goto err_class; 4106ee959b00STony Jones if (device_create_file(&host->dev, &dev_attr_port)) 4107aef9ec39SRoland Dreier goto err_class; 4108aef9ec39SRoland Dreier 4109aef9ec39SRoland Dreier return host; 4110aef9ec39SRoland Dreier 4111aef9ec39SRoland Dreier err_class: 4112ee959b00STony Jones device_unregister(&host->dev); 4113aef9ec39SRoland Dreier 4114f5358a17SRoland Dreier free_host: 4115aef9ec39SRoland Dreier kfree(host); 4116aef9ec39SRoland Dreier 4117aef9ec39SRoland Dreier return NULL; 4118aef9ec39SRoland Dreier } 4119aef9ec39SRoland Dreier 4120dc1435c0SLeon Romanovsky static void srp_rename_dev(struct ib_device *device, void *client_data) 4121dc1435c0SLeon Romanovsky { 4122dc1435c0SLeon Romanovsky struct srp_device *srp_dev = client_data; 4123dc1435c0SLeon Romanovsky struct srp_host *host, *tmp_host; 4124dc1435c0SLeon Romanovsky 4125dc1435c0SLeon Romanovsky list_for_each_entry_safe(host, tmp_host, &srp_dev->dev_list, list) { 4126dc1435c0SLeon Romanovsky char name[IB_DEVICE_NAME_MAX + 8]; 4127dc1435c0SLeon Romanovsky 4128dc1435c0SLeon Romanovsky snprintf(name, sizeof(name), "srp-%s-%d", 4129dc1435c0SLeon Romanovsky dev_name(&device->dev), host->port); 4130dc1435c0SLeon Romanovsky device_rename(&host->dev, name); 4131dc1435c0SLeon Romanovsky } 4132dc1435c0SLeon Romanovsky } 4133dc1435c0SLeon Romanovsky 4134aef9ec39SRoland Dreier static void srp_add_one(struct ib_device *device) 4135aef9ec39SRoland Dreier { 4136f5358a17SRoland Dreier struct srp_device *srp_dev; 4137042dd765SBart Van Assche struct ib_device_attr *attr = &device->attrs; 4138aef9ec39SRoland Dreier struct srp_host *host; 4139ea1075edSJason Gunthorpe int mr_page_shift; 4140ea1075edSJason Gunthorpe unsigned int p; 414152ede08fSBart Van Assche u64 max_pages_per_mr; 41425f071777SChristoph Hellwig unsigned int flags = 0; 4143aef9ec39SRoland Dreier 4144249f0656SBart Van Assche srp_dev = kzalloc(sizeof(*srp_dev), GFP_KERNEL); 4145f5358a17SRoland Dreier if (!srp_dev) 41464a061b28SOr Gerlitz return; 4147f5358a17SRoland Dreier 4148f5358a17SRoland Dreier /* 4149f5358a17SRoland Dreier * Use the smallest page size supported by the HCA, down to a 41508f26c9ffSDavid Dillow * minimum of 4096 bytes. We're unlikely to build large sglists 41518f26c9ffSDavid Dillow * out of smaller entries. 4152f5358a17SRoland Dreier */ 4153042dd765SBart Van Assche mr_page_shift = max(12, ffs(attr->page_size_cap) - 1); 415452ede08fSBart Van Assche srp_dev->mr_page_size = 1 << mr_page_shift; 415552ede08fSBart Van Assche srp_dev->mr_page_mask = ~((u64) srp_dev->mr_page_size - 1); 4156042dd765SBart Van Assche max_pages_per_mr = attr->max_mr_size; 415752ede08fSBart Van Assche do_div(max_pages_per_mr, srp_dev->mr_page_size); 4158509c5f33SBart Van Assche pr_debug("%s: %llu / %u = %llu <> %u\n", __func__, 4159042dd765SBart Van Assche attr->max_mr_size, srp_dev->mr_page_size, 4160509c5f33SBart Van Assche max_pages_per_mr, SRP_MAX_PAGES_PER_MR); 416152ede08fSBart Van Assche srp_dev->max_pages_per_mr = min_t(u64, SRP_MAX_PAGES_PER_MR, 416252ede08fSBart Van Assche max_pages_per_mr); 4163835ee624SBart Van Assche 41643023a1e9SKamal Heib srp_dev->has_fmr = (device->ops.alloc_fmr && 41653023a1e9SKamal Heib device->ops.dealloc_fmr && 41663023a1e9SKamal Heib device->ops.map_phys_fmr && 41673023a1e9SKamal Heib device->ops.unmap_fmr); 4168042dd765SBart Van Assche srp_dev->has_fr = (attr->device_cap_flags & 4169835ee624SBart Van Assche IB_DEVICE_MEM_MGT_EXTENSIONS); 4170c222a39fSBart Van Assche if (!never_register && !srp_dev->has_fmr && !srp_dev->has_fr) { 4171835ee624SBart Van Assche dev_warn(&device->dev, "neither FMR nor FR is supported\n"); 4172c222a39fSBart Van Assche } else if (!never_register && 4173042dd765SBart Van Assche attr->max_mr_size >= 2 * srp_dev->mr_page_size) { 4174835ee624SBart Van Assche srp_dev->use_fast_reg = (srp_dev->has_fr && 4175835ee624SBart Van Assche (!srp_dev->has_fmr || prefer_fr)); 4176835ee624SBart Van Assche srp_dev->use_fmr = !srp_dev->use_fast_reg && srp_dev->has_fmr; 4177509c5f33SBart Van Assche } 4178835ee624SBart Van Assche 41795f071777SChristoph Hellwig if (never_register || !register_always || 41805f071777SChristoph Hellwig (!srp_dev->has_fmr && !srp_dev->has_fr)) 41815f071777SChristoph Hellwig flags |= IB_PD_UNSAFE_GLOBAL_RKEY; 41825f071777SChristoph Hellwig 41835cfb1782SBart Van Assche if (srp_dev->use_fast_reg) { 41845cfb1782SBart Van Assche srp_dev->max_pages_per_mr = 41855cfb1782SBart Van Assche min_t(u32, srp_dev->max_pages_per_mr, 4186042dd765SBart Van Assche attr->max_fast_reg_page_list_len); 41875cfb1782SBart Van Assche } 418852ede08fSBart Van Assche srp_dev->mr_max_size = srp_dev->mr_page_size * 418952ede08fSBart Van Assche srp_dev->max_pages_per_mr; 41904a061b28SOr 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", 41916c854111SJason Gunthorpe dev_name(&device->dev), mr_page_shift, attr->max_mr_size, 4192042dd765SBart Van Assche attr->max_fast_reg_page_list_len, 419352ede08fSBart Van Assche srp_dev->max_pages_per_mr, srp_dev->mr_max_size); 4194f5358a17SRoland Dreier 4195f5358a17SRoland Dreier INIT_LIST_HEAD(&srp_dev->dev_list); 4196f5358a17SRoland Dreier 4197f5358a17SRoland Dreier srp_dev->dev = device; 41985f071777SChristoph Hellwig srp_dev->pd = ib_alloc_pd(device, flags); 4199f5358a17SRoland Dreier if (IS_ERR(srp_dev->pd)) 4200f5358a17SRoland Dreier goto free_dev; 4201f5358a17SRoland Dreier 4202cee687b6SBart Van Assche if (flags & IB_PD_UNSAFE_GLOBAL_RKEY) { 4203cee687b6SBart Van Assche srp_dev->global_rkey = srp_dev->pd->unsafe_global_rkey; 4204cee687b6SBart Van Assche WARN_ON_ONCE(srp_dev->global_rkey == 0); 4205cee687b6SBart Van Assche } 4206f5358a17SRoland Dreier 4207ea1075edSJason Gunthorpe rdma_for_each_port (device, p) { 4208f5358a17SRoland Dreier host = srp_add_port(srp_dev, p); 4209aef9ec39SRoland Dreier if (host) 4210f5358a17SRoland Dreier list_add_tail(&host->list, &srp_dev->dev_list); 4211aef9ec39SRoland Dreier } 4212aef9ec39SRoland Dreier 4213f5358a17SRoland Dreier ib_set_client_data(device, &srp_client, srp_dev); 42144a061b28SOr Gerlitz return; 4215f5358a17SRoland Dreier 4216f5358a17SRoland Dreier free_dev: 4217f5358a17SRoland Dreier kfree(srp_dev); 4218aef9ec39SRoland Dreier } 4219aef9ec39SRoland Dreier 42207c1eb45aSHaggai Eran static void srp_remove_one(struct ib_device *device, void *client_data) 4221aef9ec39SRoland Dreier { 4222f5358a17SRoland Dreier struct srp_device *srp_dev; 4223aef9ec39SRoland Dreier struct srp_host *host, *tmp_host; 4224ef6c49d8SBart Van Assche struct srp_target_port *target; 4225aef9ec39SRoland Dreier 42267c1eb45aSHaggai Eran srp_dev = client_data; 42271fe0cb84SDotan Barak if (!srp_dev) 42281fe0cb84SDotan Barak return; 4229aef9ec39SRoland Dreier 4230f5358a17SRoland Dreier list_for_each_entry_safe(host, tmp_host, &srp_dev->dev_list, list) { 4231ee959b00STony Jones device_unregister(&host->dev); 4232aef9ec39SRoland Dreier /* 4233aef9ec39SRoland Dreier * Wait for the sysfs entry to go away, so that no new 4234aef9ec39SRoland Dreier * target ports can be created. 4235aef9ec39SRoland Dreier */ 4236aef9ec39SRoland Dreier wait_for_completion(&host->released); 4237aef9ec39SRoland Dreier 4238aef9ec39SRoland Dreier /* 4239ef6c49d8SBart Van Assche * Remove all target ports. 4240aef9ec39SRoland Dreier */ 4241b3589fd4SMatthew Wilcox spin_lock(&host->target_lock); 4242ef6c49d8SBart Van Assche list_for_each_entry(target, &host->target_list, list) 4243ef6c49d8SBart Van Assche srp_queue_remove_work(target); 4244b3589fd4SMatthew Wilcox spin_unlock(&host->target_lock); 4245aef9ec39SRoland Dreier 4246aef9ec39SRoland Dreier /* 4247bcc05910SBart Van Assche * Wait for tl_err and target port removal tasks. 4248aef9ec39SRoland Dreier */ 4249ef6c49d8SBart Van Assche flush_workqueue(system_long_wq); 4250bcc05910SBart Van Assche flush_workqueue(srp_remove_wq); 4251aef9ec39SRoland Dreier 4252aef9ec39SRoland Dreier kfree(host); 4253aef9ec39SRoland Dreier } 4254aef9ec39SRoland Dreier 4255f5358a17SRoland Dreier ib_dealloc_pd(srp_dev->pd); 4256f5358a17SRoland Dreier 4257f5358a17SRoland Dreier kfree(srp_dev); 4258aef9ec39SRoland Dreier } 4259aef9ec39SRoland Dreier 42603236822bSFUJITA Tomonori static struct srp_function_template ib_srp_transport_functions = { 4261ed9b2264SBart Van Assche .has_rport_state = true, 4262ed9b2264SBart Van Assche .reset_timer_if_blocked = true, 4263a95cadb9SBart Van Assche .reconnect_delay = &srp_reconnect_delay, 4264ed9b2264SBart Van Assche .fast_io_fail_tmo = &srp_fast_io_fail_tmo, 4265ed9b2264SBart Van Assche .dev_loss_tmo = &srp_dev_loss_tmo, 4266ed9b2264SBart Van Assche .reconnect = srp_rport_reconnect, 4267dc1bdbd9SBart Van Assche .rport_delete = srp_rport_delete, 4268ed9b2264SBart Van Assche .terminate_rport_io = srp_terminate_io, 42693236822bSFUJITA Tomonori }; 42703236822bSFUJITA Tomonori 4271aef9ec39SRoland Dreier static int __init srp_init_module(void) 4272aef9ec39SRoland Dreier { 4273aef9ec39SRoland Dreier int ret; 4274aef9ec39SRoland Dreier 427516d14e01SBart Van Assche BUILD_BUG_ON(sizeof(struct srp_imm_buf) != 4); 427616d14e01SBart Van Assche BUILD_BUG_ON(sizeof(struct srp_login_req) != 64); 427716d14e01SBart Van Assche BUILD_BUG_ON(sizeof(struct srp_login_req_rdma) != 56); 427816d14e01SBart Van Assche BUILD_BUG_ON(sizeof(struct srp_cmd) != 48); 427916d14e01SBart Van Assche 428049248644SDavid Dillow if (srp_sg_tablesize) { 4281e0bda7d8SBart Van Assche pr_warn("srp_sg_tablesize is deprecated, please use cmd_sg_entries\n"); 428249248644SDavid Dillow if (!cmd_sg_entries) 428349248644SDavid Dillow cmd_sg_entries = srp_sg_tablesize; 428449248644SDavid Dillow } 428549248644SDavid Dillow 428649248644SDavid Dillow if (!cmd_sg_entries) 428749248644SDavid Dillow cmd_sg_entries = SRP_DEF_SG_TABLESIZE; 428849248644SDavid Dillow 428949248644SDavid Dillow if (cmd_sg_entries > 255) { 4290e0bda7d8SBart Van Assche pr_warn("Clamping cmd_sg_entries to 255\n"); 429149248644SDavid Dillow cmd_sg_entries = 255; 42921e89a194SDavid Dillow } 42931e89a194SDavid Dillow 4294c07d424dSDavid Dillow if (!indirect_sg_entries) 4295c07d424dSDavid Dillow indirect_sg_entries = cmd_sg_entries; 4296c07d424dSDavid Dillow else if (indirect_sg_entries < cmd_sg_entries) { 4297e0bda7d8SBart Van Assche pr_warn("Bumping up indirect_sg_entries to match cmd_sg_entries (%u)\n", 4298e0bda7d8SBart Van Assche cmd_sg_entries); 4299c07d424dSDavid Dillow indirect_sg_entries = cmd_sg_entries; 4300c07d424dSDavid Dillow } 4301c07d424dSDavid Dillow 43020a475ef4SIsrael Rukshin if (indirect_sg_entries > SG_MAX_SEGMENTS) { 43030a475ef4SIsrael Rukshin pr_warn("Clamping indirect_sg_entries to %u\n", 43040a475ef4SIsrael Rukshin SG_MAX_SEGMENTS); 43050a475ef4SIsrael Rukshin indirect_sg_entries = SG_MAX_SEGMENTS; 43060a475ef4SIsrael Rukshin } 43070a475ef4SIsrael Rukshin 4308bcc05910SBart Van Assche srp_remove_wq = create_workqueue("srp_remove"); 4309da05be29SWei Yongjun if (!srp_remove_wq) { 4310da05be29SWei Yongjun ret = -ENOMEM; 4311bcc05910SBart Van Assche goto out; 4312bcc05910SBart Van Assche } 4313bcc05910SBart Van Assche 4314bcc05910SBart Van Assche ret = -ENOMEM; 43153236822bSFUJITA Tomonori ib_srp_transport_template = 43163236822bSFUJITA Tomonori srp_attach_transport(&ib_srp_transport_functions); 43173236822bSFUJITA Tomonori if (!ib_srp_transport_template) 4318bcc05910SBart Van Assche goto destroy_wq; 43193236822bSFUJITA Tomonori 4320aef9ec39SRoland Dreier ret = class_register(&srp_class); 4321aef9ec39SRoland Dreier if (ret) { 4322e0bda7d8SBart Van Assche pr_err("couldn't register class infiniband_srp\n"); 4323bcc05910SBart Van Assche goto release_tr; 4324aef9ec39SRoland Dreier } 4325aef9ec39SRoland Dreier 4326c1a0b23bSMichael S. Tsirkin ib_sa_register_client(&srp_sa_client); 4327c1a0b23bSMichael S. Tsirkin 4328aef9ec39SRoland Dreier ret = ib_register_client(&srp_client); 4329aef9ec39SRoland Dreier if (ret) { 4330e0bda7d8SBart Van Assche pr_err("couldn't register IB client\n"); 4331bcc05910SBart Van Assche goto unreg_sa; 4332aef9ec39SRoland Dreier } 4333aef9ec39SRoland Dreier 4334bcc05910SBart Van Assche out: 4335bcc05910SBart Van Assche return ret; 4336bcc05910SBart Van Assche 4337bcc05910SBart Van Assche unreg_sa: 4338bcc05910SBart Van Assche ib_sa_unregister_client(&srp_sa_client); 4339bcc05910SBart Van Assche class_unregister(&srp_class); 4340bcc05910SBart Van Assche 4341bcc05910SBart Van Assche release_tr: 4342bcc05910SBart Van Assche srp_release_transport(ib_srp_transport_template); 4343bcc05910SBart Van Assche 4344bcc05910SBart Van Assche destroy_wq: 4345bcc05910SBart Van Assche destroy_workqueue(srp_remove_wq); 4346bcc05910SBart Van Assche goto out; 4347aef9ec39SRoland Dreier } 4348aef9ec39SRoland Dreier 4349aef9ec39SRoland Dreier static void __exit srp_cleanup_module(void) 4350aef9ec39SRoland Dreier { 4351aef9ec39SRoland Dreier ib_unregister_client(&srp_client); 4352c1a0b23bSMichael S. Tsirkin ib_sa_unregister_client(&srp_sa_client); 4353aef9ec39SRoland Dreier class_unregister(&srp_class); 43543236822bSFUJITA Tomonori srp_release_transport(ib_srp_transport_template); 4355bcc05910SBart Van Assche destroy_workqueue(srp_remove_wq); 4356aef9ec39SRoland Dreier } 4357aef9ec39SRoland Dreier 4358aef9ec39SRoland Dreier module_init(srp_init_module); 4359aef9ec39SRoland Dreier module_exit(srp_cleanup_module); 4360