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> 43aef9ec39SRoland Dreier 4460063497SArun Sharma #include <linux/atomic.h> 45aef9ec39SRoland Dreier 46aef9ec39SRoland Dreier #include <scsi/scsi.h> 47aef9ec39SRoland Dreier #include <scsi/scsi_device.h> 48aef9ec39SRoland Dreier #include <scsi/scsi_dbg.h> 4971444b97SJack Wang #include <scsi/scsi_tcq.h> 50aef9ec39SRoland Dreier #include <scsi/srp.h> 513236822bSFUJITA Tomonori #include <scsi/scsi_transport_srp.h> 52aef9ec39SRoland Dreier 53aef9ec39SRoland Dreier #include "ib_srp.h" 54aef9ec39SRoland Dreier 55aef9ec39SRoland Dreier #define DRV_NAME "ib_srp" 56aef9ec39SRoland Dreier #define PFX DRV_NAME ": " 57e8ca4135SVu Pham #define DRV_VERSION "1.0" 58e8ca4135SVu Pham #define DRV_RELDATE "July 1, 2013" 59aef9ec39SRoland Dreier 60aef9ec39SRoland Dreier MODULE_AUTHOR("Roland Dreier"); 61aef9ec39SRoland Dreier MODULE_DESCRIPTION("InfiniBand SCSI RDMA Protocol initiator " 62aef9ec39SRoland Dreier "v" DRV_VERSION " (" DRV_RELDATE ")"); 63aef9ec39SRoland Dreier MODULE_LICENSE("Dual BSD/GPL"); 64aef9ec39SRoland Dreier 6549248644SDavid Dillow static unsigned int srp_sg_tablesize; 6649248644SDavid Dillow static unsigned int cmd_sg_entries; 67c07d424dSDavid Dillow static unsigned int indirect_sg_entries; 68c07d424dSDavid Dillow static bool allow_ext_sg; 695cfb1782SBart Van Assche static bool prefer_fr; 70b1b8854dSBart Van Assche static bool register_always; 71aef9ec39SRoland Dreier static int topspin_workarounds = 1; 72aef9ec39SRoland Dreier 7349248644SDavid Dillow module_param(srp_sg_tablesize, uint, 0444); 7449248644SDavid Dillow MODULE_PARM_DESC(srp_sg_tablesize, "Deprecated name for cmd_sg_entries"); 7549248644SDavid Dillow 7649248644SDavid Dillow module_param(cmd_sg_entries, uint, 0444); 7749248644SDavid Dillow MODULE_PARM_DESC(cmd_sg_entries, 7849248644SDavid Dillow "Default number of gather/scatter entries in the SRP command (default is 12, max 255)"); 7949248644SDavid Dillow 80c07d424dSDavid Dillow module_param(indirect_sg_entries, uint, 0444); 81c07d424dSDavid Dillow MODULE_PARM_DESC(indirect_sg_entries, 82c07d424dSDavid Dillow "Default max number of gather/scatter entries (default is 12, max is " __stringify(SCSI_MAX_SG_CHAIN_SEGMENTS) ")"); 83c07d424dSDavid Dillow 84c07d424dSDavid Dillow module_param(allow_ext_sg, bool, 0444); 85c07d424dSDavid Dillow MODULE_PARM_DESC(allow_ext_sg, 86c07d424dSDavid Dillow "Default behavior when there are more than cmd_sg_entries S/G entries after mapping; fails the request when false (default false)"); 87c07d424dSDavid Dillow 88aef9ec39SRoland Dreier module_param(topspin_workarounds, int, 0444); 89aef9ec39SRoland Dreier MODULE_PARM_DESC(topspin_workarounds, 90aef9ec39SRoland Dreier "Enable workarounds for Topspin/Cisco SRP target bugs if != 0"); 91aef9ec39SRoland Dreier 925cfb1782SBart Van Assche module_param(prefer_fr, bool, 0444); 935cfb1782SBart Van Assche MODULE_PARM_DESC(prefer_fr, 945cfb1782SBart Van Assche "Whether to use fast registration if both FMR and fast registration are supported"); 955cfb1782SBart Van Assche 96b1b8854dSBart Van Assche module_param(register_always, bool, 0444); 97b1b8854dSBart Van Assche MODULE_PARM_DESC(register_always, 98b1b8854dSBart Van Assche "Use memory registration even for contiguous memory regions"); 99b1b8854dSBart Van Assche 100ed9b2264SBart Van Assche static struct kernel_param_ops srp_tmo_ops; 101ed9b2264SBart Van Assche 102a95cadb9SBart Van Assche static int srp_reconnect_delay = 10; 103a95cadb9SBart Van Assche module_param_cb(reconnect_delay, &srp_tmo_ops, &srp_reconnect_delay, 104a95cadb9SBart Van Assche S_IRUGO | S_IWUSR); 105a95cadb9SBart Van Assche MODULE_PARM_DESC(reconnect_delay, "Time between successive reconnect attempts"); 106a95cadb9SBart Van Assche 107ed9b2264SBart Van Assche static int srp_fast_io_fail_tmo = 15; 108ed9b2264SBart Van Assche module_param_cb(fast_io_fail_tmo, &srp_tmo_ops, &srp_fast_io_fail_tmo, 109ed9b2264SBart Van Assche S_IRUGO | S_IWUSR); 110ed9b2264SBart Van Assche MODULE_PARM_DESC(fast_io_fail_tmo, 111ed9b2264SBart Van Assche "Number of seconds between the observation of a transport" 112ed9b2264SBart Van Assche " layer error and failing all I/O. \"off\" means that this" 113ed9b2264SBart Van Assche " functionality is disabled."); 114ed9b2264SBart Van Assche 115a95cadb9SBart Van Assche static int srp_dev_loss_tmo = 600; 116ed9b2264SBart Van Assche module_param_cb(dev_loss_tmo, &srp_tmo_ops, &srp_dev_loss_tmo, 117ed9b2264SBart Van Assche S_IRUGO | S_IWUSR); 118ed9b2264SBart Van Assche MODULE_PARM_DESC(dev_loss_tmo, 119ed9b2264SBart Van Assche "Maximum number of seconds that the SRP transport should" 120ed9b2264SBart Van Assche " insulate transport layer errors. After this time has been" 121ed9b2264SBart Van Assche " exceeded the SCSI host is removed. Should be" 122ed9b2264SBart Van Assche " between 1 and " __stringify(SCSI_DEVICE_BLOCK_MAX_TIMEOUT) 123ed9b2264SBart Van Assche " if fast_io_fail_tmo has not been set. \"off\" means that" 124ed9b2264SBart Van Assche " this functionality is disabled."); 125ed9b2264SBart Van Assche 126aef9ec39SRoland Dreier static void srp_add_one(struct ib_device *device); 127aef9ec39SRoland Dreier static void srp_remove_one(struct ib_device *device); 1289c03dc9fSBart Van Assche static void srp_recv_completion(struct ib_cq *cq, void *target_ptr); 1299c03dc9fSBart Van Assche static void srp_send_completion(struct ib_cq *cq, void *target_ptr); 130aef9ec39SRoland Dreier static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event); 131aef9ec39SRoland Dreier 1323236822bSFUJITA Tomonori static struct scsi_transport_template *ib_srp_transport_template; 133bcc05910SBart Van Assche static struct workqueue_struct *srp_remove_wq; 1343236822bSFUJITA Tomonori 135aef9ec39SRoland Dreier static struct ib_client srp_client = { 136aef9ec39SRoland Dreier .name = "srp", 137aef9ec39SRoland Dreier .add = srp_add_one, 138aef9ec39SRoland Dreier .remove = srp_remove_one 139aef9ec39SRoland Dreier }; 140aef9ec39SRoland Dreier 141c1a0b23bSMichael S. Tsirkin static struct ib_sa_client srp_sa_client; 142c1a0b23bSMichael S. Tsirkin 143ed9b2264SBart Van Assche static int srp_tmo_get(char *buffer, const struct kernel_param *kp) 144ed9b2264SBart Van Assche { 145ed9b2264SBart Van Assche int tmo = *(int *)kp->arg; 146ed9b2264SBart Van Assche 147ed9b2264SBart Van Assche if (tmo >= 0) 148ed9b2264SBart Van Assche return sprintf(buffer, "%d", tmo); 149ed9b2264SBart Van Assche else 150ed9b2264SBart Van Assche return sprintf(buffer, "off"); 151ed9b2264SBart Van Assche } 152ed9b2264SBart Van Assche 153ed9b2264SBart Van Assche static int srp_tmo_set(const char *val, const struct kernel_param *kp) 154ed9b2264SBart Van Assche { 155ed9b2264SBart Van Assche int tmo, res; 156ed9b2264SBart Van Assche 157ed9b2264SBart Van Assche if (strncmp(val, "off", 3) != 0) { 158ed9b2264SBart Van Assche res = kstrtoint(val, 0, &tmo); 159ed9b2264SBart Van Assche if (res) 160ed9b2264SBart Van Assche goto out; 161ed9b2264SBart Van Assche } else { 162ed9b2264SBart Van Assche tmo = -1; 163ed9b2264SBart Van Assche } 164a95cadb9SBart Van Assche if (kp->arg == &srp_reconnect_delay) 165a95cadb9SBart Van Assche res = srp_tmo_valid(tmo, srp_fast_io_fail_tmo, 166a95cadb9SBart Van Assche srp_dev_loss_tmo); 167a95cadb9SBart Van Assche else if (kp->arg == &srp_fast_io_fail_tmo) 168a95cadb9SBart Van Assche res = srp_tmo_valid(srp_reconnect_delay, tmo, srp_dev_loss_tmo); 169ed9b2264SBart Van Assche else 170a95cadb9SBart Van Assche res = srp_tmo_valid(srp_reconnect_delay, srp_fast_io_fail_tmo, 171a95cadb9SBart Van Assche tmo); 172ed9b2264SBart Van Assche if (res) 173ed9b2264SBart Van Assche goto out; 174ed9b2264SBart Van Assche *(int *)kp->arg = tmo; 175ed9b2264SBart Van Assche 176ed9b2264SBart Van Assche out: 177ed9b2264SBart Van Assche return res; 178ed9b2264SBart Van Assche } 179ed9b2264SBart Van Assche 180ed9b2264SBart Van Assche static struct kernel_param_ops srp_tmo_ops = { 181ed9b2264SBart Van Assche .get = srp_tmo_get, 182ed9b2264SBart Van Assche .set = srp_tmo_set, 183ed9b2264SBart Van Assche }; 184ed9b2264SBart Van Assche 185aef9ec39SRoland Dreier static inline struct srp_target_port *host_to_target(struct Scsi_Host *host) 186aef9ec39SRoland Dreier { 187aef9ec39SRoland Dreier return (struct srp_target_port *) host->hostdata; 188aef9ec39SRoland Dreier } 189aef9ec39SRoland Dreier 190aef9ec39SRoland Dreier static const char *srp_target_info(struct Scsi_Host *host) 191aef9ec39SRoland Dreier { 192aef9ec39SRoland Dreier return host_to_target(host)->target_name; 193aef9ec39SRoland Dreier } 194aef9ec39SRoland Dreier 1955d7cbfd6SRoland Dreier static int srp_target_is_topspin(struct srp_target_port *target) 1965d7cbfd6SRoland Dreier { 1975d7cbfd6SRoland Dreier static const u8 topspin_oui[3] = { 0x00, 0x05, 0xad }; 1983d1ff48dSRaghava Kondapalli static const u8 cisco_oui[3] = { 0x00, 0x1b, 0x0d }; 1995d7cbfd6SRoland Dreier 2005d7cbfd6SRoland Dreier return topspin_workarounds && 2013d1ff48dSRaghava Kondapalli (!memcmp(&target->ioc_guid, topspin_oui, sizeof topspin_oui) || 2023d1ff48dSRaghava Kondapalli !memcmp(&target->ioc_guid, cisco_oui, sizeof cisco_oui)); 2035d7cbfd6SRoland Dreier } 2045d7cbfd6SRoland Dreier 205aef9ec39SRoland Dreier static struct srp_iu *srp_alloc_iu(struct srp_host *host, size_t size, 206aef9ec39SRoland Dreier gfp_t gfp_mask, 207aef9ec39SRoland Dreier enum dma_data_direction direction) 208aef9ec39SRoland Dreier { 209aef9ec39SRoland Dreier struct srp_iu *iu; 210aef9ec39SRoland Dreier 211aef9ec39SRoland Dreier iu = kmalloc(sizeof *iu, gfp_mask); 212aef9ec39SRoland Dreier if (!iu) 213aef9ec39SRoland Dreier goto out; 214aef9ec39SRoland Dreier 215aef9ec39SRoland Dreier iu->buf = kzalloc(size, gfp_mask); 216aef9ec39SRoland Dreier if (!iu->buf) 217aef9ec39SRoland Dreier goto out_free_iu; 218aef9ec39SRoland Dreier 21905321937SGreg Kroah-Hartman iu->dma = ib_dma_map_single(host->srp_dev->dev, iu->buf, size, 22005321937SGreg Kroah-Hartman direction); 22105321937SGreg Kroah-Hartman if (ib_dma_mapping_error(host->srp_dev->dev, iu->dma)) 222aef9ec39SRoland Dreier goto out_free_buf; 223aef9ec39SRoland Dreier 224aef9ec39SRoland Dreier iu->size = size; 225aef9ec39SRoland Dreier iu->direction = direction; 226aef9ec39SRoland Dreier 227aef9ec39SRoland Dreier return iu; 228aef9ec39SRoland Dreier 229aef9ec39SRoland Dreier out_free_buf: 230aef9ec39SRoland Dreier kfree(iu->buf); 231aef9ec39SRoland Dreier out_free_iu: 232aef9ec39SRoland Dreier kfree(iu); 233aef9ec39SRoland Dreier out: 234aef9ec39SRoland Dreier return NULL; 235aef9ec39SRoland Dreier } 236aef9ec39SRoland Dreier 237aef9ec39SRoland Dreier static void srp_free_iu(struct srp_host *host, struct srp_iu *iu) 238aef9ec39SRoland Dreier { 239aef9ec39SRoland Dreier if (!iu) 240aef9ec39SRoland Dreier return; 241aef9ec39SRoland Dreier 24205321937SGreg Kroah-Hartman ib_dma_unmap_single(host->srp_dev->dev, iu->dma, iu->size, 24305321937SGreg Kroah-Hartman iu->direction); 244aef9ec39SRoland Dreier kfree(iu->buf); 245aef9ec39SRoland Dreier kfree(iu); 246aef9ec39SRoland Dreier } 247aef9ec39SRoland Dreier 248aef9ec39SRoland Dreier static void srp_qp_event(struct ib_event *event, void *context) 249aef9ec39SRoland Dreier { 250e0bda7d8SBart Van Assche pr_debug("QP event %d\n", event->event); 251aef9ec39SRoland Dreier } 252aef9ec39SRoland Dreier 253aef9ec39SRoland Dreier static int srp_init_qp(struct srp_target_port *target, 254aef9ec39SRoland Dreier struct ib_qp *qp) 255aef9ec39SRoland Dreier { 256aef9ec39SRoland Dreier struct ib_qp_attr *attr; 257aef9ec39SRoland Dreier int ret; 258aef9ec39SRoland Dreier 259aef9ec39SRoland Dreier attr = kmalloc(sizeof *attr, GFP_KERNEL); 260aef9ec39SRoland Dreier if (!attr) 261aef9ec39SRoland Dreier return -ENOMEM; 262aef9ec39SRoland Dreier 263969a60f9SRoland Dreier ret = ib_find_pkey(target->srp_host->srp_dev->dev, 264aef9ec39SRoland Dreier target->srp_host->port, 265aef9ec39SRoland Dreier be16_to_cpu(target->path.pkey), 266aef9ec39SRoland Dreier &attr->pkey_index); 267aef9ec39SRoland Dreier if (ret) 268aef9ec39SRoland Dreier goto out; 269aef9ec39SRoland Dreier 270aef9ec39SRoland Dreier attr->qp_state = IB_QPS_INIT; 271aef9ec39SRoland Dreier attr->qp_access_flags = (IB_ACCESS_REMOTE_READ | 272aef9ec39SRoland Dreier IB_ACCESS_REMOTE_WRITE); 273aef9ec39SRoland Dreier attr->port_num = target->srp_host->port; 274aef9ec39SRoland Dreier 275aef9ec39SRoland Dreier ret = ib_modify_qp(qp, attr, 276aef9ec39SRoland Dreier IB_QP_STATE | 277aef9ec39SRoland Dreier IB_QP_PKEY_INDEX | 278aef9ec39SRoland Dreier IB_QP_ACCESS_FLAGS | 279aef9ec39SRoland Dreier IB_QP_PORT); 280aef9ec39SRoland Dreier 281aef9ec39SRoland Dreier out: 282aef9ec39SRoland Dreier kfree(attr); 283aef9ec39SRoland Dreier return ret; 284aef9ec39SRoland Dreier } 285aef9ec39SRoland Dreier 2869fe4bcf4SDavid Dillow static int srp_new_cm_id(struct srp_target_port *target) 2879fe4bcf4SDavid Dillow { 2889fe4bcf4SDavid Dillow struct ib_cm_id *new_cm_id; 2899fe4bcf4SDavid Dillow 29005321937SGreg Kroah-Hartman new_cm_id = ib_create_cm_id(target->srp_host->srp_dev->dev, 2919fe4bcf4SDavid Dillow srp_cm_handler, target); 2929fe4bcf4SDavid Dillow if (IS_ERR(new_cm_id)) 2939fe4bcf4SDavid Dillow return PTR_ERR(new_cm_id); 2949fe4bcf4SDavid Dillow 2959fe4bcf4SDavid Dillow if (target->cm_id) 2969fe4bcf4SDavid Dillow ib_destroy_cm_id(target->cm_id); 2979fe4bcf4SDavid Dillow target->cm_id = new_cm_id; 2989fe4bcf4SDavid Dillow 2999fe4bcf4SDavid Dillow return 0; 3009fe4bcf4SDavid Dillow } 3019fe4bcf4SDavid Dillow 302d1b4289eSBart Van Assche static struct ib_fmr_pool *srp_alloc_fmr_pool(struct srp_target_port *target) 303d1b4289eSBart Van Assche { 304d1b4289eSBart Van Assche struct srp_device *dev = target->srp_host->srp_dev; 305d1b4289eSBart Van Assche struct ib_fmr_pool_param fmr_param; 306d1b4289eSBart Van Assche 307d1b4289eSBart Van Assche memset(&fmr_param, 0, sizeof(fmr_param)); 308d1b4289eSBart Van Assche fmr_param.pool_size = target->scsi_host->can_queue; 309d1b4289eSBart Van Assche fmr_param.dirty_watermark = fmr_param.pool_size / 4; 310d1b4289eSBart Van Assche fmr_param.cache = 1; 31152ede08fSBart Van Assche fmr_param.max_pages_per_fmr = dev->max_pages_per_mr; 31252ede08fSBart Van Assche fmr_param.page_shift = ilog2(dev->mr_page_size); 313d1b4289eSBart Van Assche fmr_param.access = (IB_ACCESS_LOCAL_WRITE | 314d1b4289eSBart Van Assche IB_ACCESS_REMOTE_WRITE | 315d1b4289eSBart Van Assche IB_ACCESS_REMOTE_READ); 316d1b4289eSBart Van Assche 317d1b4289eSBart Van Assche return ib_create_fmr_pool(dev->pd, &fmr_param); 318d1b4289eSBart Van Assche } 319d1b4289eSBart Van Assche 3205cfb1782SBart Van Assche /** 3215cfb1782SBart Van Assche * srp_destroy_fr_pool() - free the resources owned by a pool 3225cfb1782SBart Van Assche * @pool: Fast registration pool to be destroyed. 3235cfb1782SBart Van Assche */ 3245cfb1782SBart Van Assche static void srp_destroy_fr_pool(struct srp_fr_pool *pool) 3255cfb1782SBart Van Assche { 3265cfb1782SBart Van Assche int i; 3275cfb1782SBart Van Assche struct srp_fr_desc *d; 3285cfb1782SBart Van Assche 3295cfb1782SBart Van Assche if (!pool) 3305cfb1782SBart Van Assche return; 3315cfb1782SBart Van Assche 3325cfb1782SBart Van Assche for (i = 0, d = &pool->desc[0]; i < pool->size; i++, d++) { 3335cfb1782SBart Van Assche if (d->frpl) 3345cfb1782SBart Van Assche ib_free_fast_reg_page_list(d->frpl); 3355cfb1782SBart Van Assche if (d->mr) 3365cfb1782SBart Van Assche ib_dereg_mr(d->mr); 3375cfb1782SBart Van Assche } 3385cfb1782SBart Van Assche kfree(pool); 3395cfb1782SBart Van Assche } 3405cfb1782SBart Van Assche 3415cfb1782SBart Van Assche /** 3425cfb1782SBart Van Assche * srp_create_fr_pool() - allocate and initialize a pool for fast registration 3435cfb1782SBart Van Assche * @device: IB device to allocate fast registration descriptors for. 3445cfb1782SBart Van Assche * @pd: Protection domain associated with the FR descriptors. 3455cfb1782SBart Van Assche * @pool_size: Number of descriptors to allocate. 3465cfb1782SBart Van Assche * @max_page_list_len: Maximum fast registration work request page list length. 3475cfb1782SBart Van Assche */ 3485cfb1782SBart Van Assche static struct srp_fr_pool *srp_create_fr_pool(struct ib_device *device, 3495cfb1782SBart Van Assche struct ib_pd *pd, int pool_size, 3505cfb1782SBart Van Assche int max_page_list_len) 3515cfb1782SBart Van Assche { 3525cfb1782SBart Van Assche struct srp_fr_pool *pool; 3535cfb1782SBart Van Assche struct srp_fr_desc *d; 3545cfb1782SBart Van Assche struct ib_mr *mr; 3555cfb1782SBart Van Assche struct ib_fast_reg_page_list *frpl; 3565cfb1782SBart Van Assche int i, ret = -EINVAL; 3575cfb1782SBart Van Assche 3585cfb1782SBart Van Assche if (pool_size <= 0) 3595cfb1782SBart Van Assche goto err; 3605cfb1782SBart Van Assche ret = -ENOMEM; 3615cfb1782SBart Van Assche pool = kzalloc(sizeof(struct srp_fr_pool) + 3625cfb1782SBart Van Assche pool_size * sizeof(struct srp_fr_desc), GFP_KERNEL); 3635cfb1782SBart Van Assche if (!pool) 3645cfb1782SBart Van Assche goto err; 3655cfb1782SBart Van Assche pool->size = pool_size; 3665cfb1782SBart Van Assche pool->max_page_list_len = max_page_list_len; 3675cfb1782SBart Van Assche spin_lock_init(&pool->lock); 3685cfb1782SBart Van Assche INIT_LIST_HEAD(&pool->free_list); 3695cfb1782SBart Van Assche 3705cfb1782SBart Van Assche for (i = 0, d = &pool->desc[0]; i < pool->size; i++, d++) { 3715cfb1782SBart Van Assche mr = ib_alloc_fast_reg_mr(pd, max_page_list_len); 3725cfb1782SBart Van Assche if (IS_ERR(mr)) { 3735cfb1782SBart Van Assche ret = PTR_ERR(mr); 3745cfb1782SBart Van Assche goto destroy_pool; 3755cfb1782SBart Van Assche } 3765cfb1782SBart Van Assche d->mr = mr; 3775cfb1782SBart Van Assche frpl = ib_alloc_fast_reg_page_list(device, max_page_list_len); 3785cfb1782SBart Van Assche if (IS_ERR(frpl)) { 3795cfb1782SBart Van Assche ret = PTR_ERR(frpl); 3805cfb1782SBart Van Assche goto destroy_pool; 3815cfb1782SBart Van Assche } 3825cfb1782SBart Van Assche d->frpl = frpl; 3835cfb1782SBart Van Assche list_add_tail(&d->entry, &pool->free_list); 3845cfb1782SBart Van Assche } 3855cfb1782SBart Van Assche 3865cfb1782SBart Van Assche out: 3875cfb1782SBart Van Assche return pool; 3885cfb1782SBart Van Assche 3895cfb1782SBart Van Assche destroy_pool: 3905cfb1782SBart Van Assche srp_destroy_fr_pool(pool); 3915cfb1782SBart Van Assche 3925cfb1782SBart Van Assche err: 3935cfb1782SBart Van Assche pool = ERR_PTR(ret); 3945cfb1782SBart Van Assche goto out; 3955cfb1782SBart Van Assche } 3965cfb1782SBart Van Assche 3975cfb1782SBart Van Assche /** 3985cfb1782SBart Van Assche * srp_fr_pool_get() - obtain a descriptor suitable for fast registration 3995cfb1782SBart Van Assche * @pool: Pool to obtain descriptor from. 4005cfb1782SBart Van Assche */ 4015cfb1782SBart Van Assche static struct srp_fr_desc *srp_fr_pool_get(struct srp_fr_pool *pool) 4025cfb1782SBart Van Assche { 4035cfb1782SBart Van Assche struct srp_fr_desc *d = NULL; 4045cfb1782SBart Van Assche unsigned long flags; 4055cfb1782SBart Van Assche 4065cfb1782SBart Van Assche spin_lock_irqsave(&pool->lock, flags); 4075cfb1782SBart Van Assche if (!list_empty(&pool->free_list)) { 4085cfb1782SBart Van Assche d = list_first_entry(&pool->free_list, typeof(*d), entry); 4095cfb1782SBart Van Assche list_del(&d->entry); 4105cfb1782SBart Van Assche } 4115cfb1782SBart Van Assche spin_unlock_irqrestore(&pool->lock, flags); 4125cfb1782SBart Van Assche 4135cfb1782SBart Van Assche return d; 4145cfb1782SBart Van Assche } 4155cfb1782SBart Van Assche 4165cfb1782SBart Van Assche /** 4175cfb1782SBart Van Assche * srp_fr_pool_put() - put an FR descriptor back in the free list 4185cfb1782SBart Van Assche * @pool: Pool the descriptor was allocated from. 4195cfb1782SBart Van Assche * @desc: Pointer to an array of fast registration descriptor pointers. 4205cfb1782SBart Van Assche * @n: Number of descriptors to put back. 4215cfb1782SBart Van Assche * 4225cfb1782SBart Van Assche * Note: The caller must already have queued an invalidation request for 4235cfb1782SBart Van Assche * desc->mr->rkey before calling this function. 4245cfb1782SBart Van Assche */ 4255cfb1782SBart Van Assche static void srp_fr_pool_put(struct srp_fr_pool *pool, struct srp_fr_desc **desc, 4265cfb1782SBart Van Assche int n) 4275cfb1782SBart Van Assche { 4285cfb1782SBart Van Assche unsigned long flags; 4295cfb1782SBart Van Assche int i; 4305cfb1782SBart Van Assche 4315cfb1782SBart Van Assche spin_lock_irqsave(&pool->lock, flags); 4325cfb1782SBart Van Assche for (i = 0; i < n; i++) 4335cfb1782SBart Van Assche list_add(&desc[i]->entry, &pool->free_list); 4345cfb1782SBart Van Assche spin_unlock_irqrestore(&pool->lock, flags); 4355cfb1782SBart Van Assche } 4365cfb1782SBart Van Assche 4375cfb1782SBart Van Assche static struct srp_fr_pool *srp_alloc_fr_pool(struct srp_target_port *target) 4385cfb1782SBart Van Assche { 4395cfb1782SBart Van Assche struct srp_device *dev = target->srp_host->srp_dev; 4405cfb1782SBart Van Assche 4415cfb1782SBart Van Assche return srp_create_fr_pool(dev->dev, dev->pd, 4425cfb1782SBart Van Assche target->scsi_host->can_queue, 4435cfb1782SBart Van Assche dev->max_pages_per_mr); 4445cfb1782SBart Van Assche } 4455cfb1782SBart Van Assche 446aef9ec39SRoland Dreier static int srp_create_target_ib(struct srp_target_port *target) 447aef9ec39SRoland Dreier { 44862154b2eSBart Van Assche struct srp_device *dev = target->srp_host->srp_dev; 449aef9ec39SRoland Dreier struct ib_qp_init_attr *init_attr; 45073aa89edSIshai Rabinovitz struct ib_cq *recv_cq, *send_cq; 45173aa89edSIshai Rabinovitz struct ib_qp *qp; 452d1b4289eSBart Van Assche struct ib_fmr_pool *fmr_pool = NULL; 4535cfb1782SBart Van Assche struct srp_fr_pool *fr_pool = NULL; 4545cfb1782SBart Van Assche const int m = 1 + dev->use_fast_reg; 455aef9ec39SRoland Dreier int ret; 456aef9ec39SRoland Dreier 457aef9ec39SRoland Dreier init_attr = kzalloc(sizeof *init_attr, GFP_KERNEL); 458aef9ec39SRoland Dreier if (!init_attr) 459aef9ec39SRoland Dreier return -ENOMEM; 460aef9ec39SRoland Dreier 46162154b2eSBart Van Assche recv_cq = ib_create_cq(dev->dev, srp_recv_completion, NULL, target, 4624d73f95fSBart Van Assche target->queue_size, target->comp_vector); 46373aa89edSIshai Rabinovitz if (IS_ERR(recv_cq)) { 46473aa89edSIshai Rabinovitz ret = PTR_ERR(recv_cq); 465da9d2f07SRoland Dreier goto err; 466aef9ec39SRoland Dreier } 467aef9ec39SRoland Dreier 46862154b2eSBart Van Assche send_cq = ib_create_cq(dev->dev, srp_send_completion, NULL, target, 4695cfb1782SBart Van Assche m * target->queue_size, target->comp_vector); 47073aa89edSIshai Rabinovitz if (IS_ERR(send_cq)) { 47173aa89edSIshai Rabinovitz ret = PTR_ERR(send_cq); 472da9d2f07SRoland Dreier goto err_recv_cq; 4739c03dc9fSBart Van Assche } 4749c03dc9fSBart Van Assche 47573aa89edSIshai Rabinovitz ib_req_notify_cq(recv_cq, IB_CQ_NEXT_COMP); 476aef9ec39SRoland Dreier 477aef9ec39SRoland Dreier init_attr->event_handler = srp_qp_event; 4785cfb1782SBart Van Assche init_attr->cap.max_send_wr = m * target->queue_size; 4794d73f95fSBart Van Assche init_attr->cap.max_recv_wr = target->queue_size; 480aef9ec39SRoland Dreier init_attr->cap.max_recv_sge = 1; 481aef9ec39SRoland Dreier init_attr->cap.max_send_sge = 1; 4825cfb1782SBart Van Assche init_attr->sq_sig_type = IB_SIGNAL_REQ_WR; 483aef9ec39SRoland Dreier init_attr->qp_type = IB_QPT_RC; 48473aa89edSIshai Rabinovitz init_attr->send_cq = send_cq; 48573aa89edSIshai Rabinovitz init_attr->recv_cq = recv_cq; 486aef9ec39SRoland Dreier 48762154b2eSBart Van Assche qp = ib_create_qp(dev->pd, init_attr); 48873aa89edSIshai Rabinovitz if (IS_ERR(qp)) { 48973aa89edSIshai Rabinovitz ret = PTR_ERR(qp); 490da9d2f07SRoland Dreier goto err_send_cq; 491aef9ec39SRoland Dreier } 492aef9ec39SRoland Dreier 49373aa89edSIshai Rabinovitz ret = srp_init_qp(target, qp); 494da9d2f07SRoland Dreier if (ret) 495da9d2f07SRoland Dreier goto err_qp; 496aef9ec39SRoland Dreier 4975cfb1782SBart Van Assche if (dev->use_fast_reg && dev->has_fr) { 4985cfb1782SBart Van Assche fr_pool = srp_alloc_fr_pool(target); 4995cfb1782SBart Van Assche if (IS_ERR(fr_pool)) { 5005cfb1782SBart Van Assche ret = PTR_ERR(fr_pool); 5015cfb1782SBart Van Assche shost_printk(KERN_WARNING, target->scsi_host, PFX 5025cfb1782SBart Van Assche "FR pool allocation failed (%d)\n", ret); 5035cfb1782SBart Van Assche goto err_qp; 5045cfb1782SBart Van Assche } 5055cfb1782SBart Van Assche if (target->fr_pool) 5065cfb1782SBart Van Assche srp_destroy_fr_pool(target->fr_pool); 5075cfb1782SBart Van Assche target->fr_pool = fr_pool; 5085cfb1782SBart Van Assche } else if (!dev->use_fast_reg && dev->has_fmr) { 509d1b4289eSBart Van Assche fmr_pool = srp_alloc_fmr_pool(target); 510d1b4289eSBart Van Assche if (IS_ERR(fmr_pool)) { 511d1b4289eSBart Van Assche ret = PTR_ERR(fmr_pool); 512d1b4289eSBart Van Assche shost_printk(KERN_WARNING, target->scsi_host, PFX 513d1b4289eSBart Van Assche "FMR pool allocation failed (%d)\n", ret); 514d1b4289eSBart Van Assche goto err_qp; 515d1b4289eSBart Van Assche } 516d1b4289eSBart Van Assche if (target->fmr_pool) 517d1b4289eSBart Van Assche ib_destroy_fmr_pool(target->fmr_pool); 518d1b4289eSBart Van Assche target->fmr_pool = fmr_pool; 519d1b4289eSBart Van Assche } 520d1b4289eSBart Van Assche 52173aa89edSIshai Rabinovitz if (target->qp) 52273aa89edSIshai Rabinovitz ib_destroy_qp(target->qp); 52373aa89edSIshai Rabinovitz if (target->recv_cq) 52473aa89edSIshai Rabinovitz ib_destroy_cq(target->recv_cq); 52573aa89edSIshai Rabinovitz if (target->send_cq) 52673aa89edSIshai Rabinovitz ib_destroy_cq(target->send_cq); 52773aa89edSIshai Rabinovitz 52873aa89edSIshai Rabinovitz target->qp = qp; 52973aa89edSIshai Rabinovitz target->recv_cq = recv_cq; 53073aa89edSIshai Rabinovitz target->send_cq = send_cq; 53173aa89edSIshai Rabinovitz 532da9d2f07SRoland Dreier kfree(init_attr); 533da9d2f07SRoland Dreier return 0; 534da9d2f07SRoland Dreier 535da9d2f07SRoland Dreier err_qp: 53673aa89edSIshai Rabinovitz ib_destroy_qp(qp); 537da9d2f07SRoland Dreier 538da9d2f07SRoland Dreier err_send_cq: 53973aa89edSIshai Rabinovitz ib_destroy_cq(send_cq); 540da9d2f07SRoland Dreier 541da9d2f07SRoland Dreier err_recv_cq: 54273aa89edSIshai Rabinovitz ib_destroy_cq(recv_cq); 543da9d2f07SRoland Dreier 544da9d2f07SRoland Dreier err: 545aef9ec39SRoland Dreier kfree(init_attr); 546aef9ec39SRoland Dreier return ret; 547aef9ec39SRoland Dreier } 548aef9ec39SRoland Dreier 5494d73f95fSBart Van Assche /* 5504d73f95fSBart Van Assche * Note: this function may be called without srp_alloc_iu_bufs() having been 5514d73f95fSBart Van Assche * invoked. Hence the target->[rt]x_ring checks. 5524d73f95fSBart Van Assche */ 553aef9ec39SRoland Dreier static void srp_free_target_ib(struct srp_target_port *target) 554aef9ec39SRoland Dreier { 5555cfb1782SBart Van Assche struct srp_device *dev = target->srp_host->srp_dev; 556aef9ec39SRoland Dreier int i; 557aef9ec39SRoland Dreier 558*394c595eSBart Van Assche if (target->cm_id) { 559*394c595eSBart Van Assche ib_destroy_cm_id(target->cm_id); 560*394c595eSBart Van Assche target->cm_id = NULL; 561*394c595eSBart Van Assche } 562*394c595eSBart Van Assche 5635cfb1782SBart Van Assche if (dev->use_fast_reg) { 5645cfb1782SBart Van Assche if (target->fr_pool) 5655cfb1782SBart Van Assche srp_destroy_fr_pool(target->fr_pool); 5665cfb1782SBart Van Assche } else { 567d1b4289eSBart Van Assche if (target->fmr_pool) 568d1b4289eSBart Van Assche ib_destroy_fmr_pool(target->fmr_pool); 5695cfb1782SBart Van Assche } 570aef9ec39SRoland Dreier ib_destroy_qp(target->qp); 5719c03dc9fSBart Van Assche ib_destroy_cq(target->send_cq); 5729c03dc9fSBart Van Assche ib_destroy_cq(target->recv_cq); 573aef9ec39SRoland Dreier 57473aa89edSIshai Rabinovitz target->qp = NULL; 57573aa89edSIshai Rabinovitz target->send_cq = target->recv_cq = NULL; 57673aa89edSIshai Rabinovitz 5774d73f95fSBart Van Assche if (target->rx_ring) { 5784d73f95fSBart Van Assche for (i = 0; i < target->queue_size; ++i) 579aef9ec39SRoland Dreier srp_free_iu(target->srp_host, target->rx_ring[i]); 5804d73f95fSBart Van Assche kfree(target->rx_ring); 5814d73f95fSBart Van Assche target->rx_ring = NULL; 5824d73f95fSBart Van Assche } 5834d73f95fSBart Van Assche if (target->tx_ring) { 5844d73f95fSBart Van Assche for (i = 0; i < target->queue_size; ++i) 585aef9ec39SRoland Dreier srp_free_iu(target->srp_host, target->tx_ring[i]); 5864d73f95fSBart Van Assche kfree(target->tx_ring); 5874d73f95fSBart Van Assche target->tx_ring = NULL; 5884d73f95fSBart Van Assche } 589aef9ec39SRoland Dreier } 590aef9ec39SRoland Dreier 591aef9ec39SRoland Dreier static void srp_path_rec_completion(int status, 592aef9ec39SRoland Dreier struct ib_sa_path_rec *pathrec, 593aef9ec39SRoland Dreier void *target_ptr) 594aef9ec39SRoland Dreier { 595aef9ec39SRoland Dreier struct srp_target_port *target = target_ptr; 596aef9ec39SRoland Dreier 597aef9ec39SRoland Dreier target->status = status; 598aef9ec39SRoland Dreier if (status) 5997aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 6007aa54bd7SDavid Dillow PFX "Got failed path rec status %d\n", status); 601aef9ec39SRoland Dreier else 602aef9ec39SRoland Dreier target->path = *pathrec; 603aef9ec39SRoland Dreier complete(&target->done); 604aef9ec39SRoland Dreier } 605aef9ec39SRoland Dreier 606aef9ec39SRoland Dreier static int srp_lookup_path(struct srp_target_port *target) 607aef9ec39SRoland Dreier { 608a702adceSBart Van Assche int ret; 609a702adceSBart Van Assche 610aef9ec39SRoland Dreier target->path.numb_path = 1; 611aef9ec39SRoland Dreier 612aef9ec39SRoland Dreier init_completion(&target->done); 613aef9ec39SRoland Dreier 614c1a0b23bSMichael S. Tsirkin target->path_query_id = ib_sa_path_rec_get(&srp_sa_client, 61505321937SGreg Kroah-Hartman target->srp_host->srp_dev->dev, 616aef9ec39SRoland Dreier target->srp_host->port, 617aef9ec39SRoland Dreier &target->path, 618247e020eSSean Hefty IB_SA_PATH_REC_SERVICE_ID | 619aef9ec39SRoland Dreier IB_SA_PATH_REC_DGID | 620aef9ec39SRoland Dreier IB_SA_PATH_REC_SGID | 621aef9ec39SRoland Dreier IB_SA_PATH_REC_NUMB_PATH | 622aef9ec39SRoland Dreier IB_SA_PATH_REC_PKEY, 623aef9ec39SRoland Dreier SRP_PATH_REC_TIMEOUT_MS, 624aef9ec39SRoland Dreier GFP_KERNEL, 625aef9ec39SRoland Dreier srp_path_rec_completion, 626aef9ec39SRoland Dreier target, &target->path_query); 627aef9ec39SRoland Dreier if (target->path_query_id < 0) 628aef9ec39SRoland Dreier return target->path_query_id; 629aef9ec39SRoland Dreier 630a702adceSBart Van Assche ret = wait_for_completion_interruptible(&target->done); 631a702adceSBart Van Assche if (ret < 0) 632a702adceSBart Van Assche return ret; 633aef9ec39SRoland Dreier 634aef9ec39SRoland Dreier if (target->status < 0) 6357aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 6367aa54bd7SDavid Dillow PFX "Path record query failed\n"); 637aef9ec39SRoland Dreier 638aef9ec39SRoland Dreier return target->status; 639aef9ec39SRoland Dreier } 640aef9ec39SRoland Dreier 641aef9ec39SRoland Dreier static int srp_send_req(struct srp_target_port *target) 642aef9ec39SRoland Dreier { 643aef9ec39SRoland Dreier struct { 644aef9ec39SRoland Dreier struct ib_cm_req_param param; 645aef9ec39SRoland Dreier struct srp_login_req priv; 646aef9ec39SRoland Dreier } *req = NULL; 647aef9ec39SRoland Dreier int status; 648aef9ec39SRoland Dreier 649aef9ec39SRoland Dreier req = kzalloc(sizeof *req, GFP_KERNEL); 650aef9ec39SRoland Dreier if (!req) 651aef9ec39SRoland Dreier return -ENOMEM; 652aef9ec39SRoland Dreier 653aef9ec39SRoland Dreier req->param.primary_path = &target->path; 654aef9ec39SRoland Dreier req->param.alternate_path = NULL; 655aef9ec39SRoland Dreier req->param.service_id = target->service_id; 656aef9ec39SRoland Dreier req->param.qp_num = target->qp->qp_num; 657aef9ec39SRoland Dreier req->param.qp_type = target->qp->qp_type; 658aef9ec39SRoland Dreier req->param.private_data = &req->priv; 659aef9ec39SRoland Dreier req->param.private_data_len = sizeof req->priv; 660aef9ec39SRoland Dreier req->param.flow_control = 1; 661aef9ec39SRoland Dreier 662aef9ec39SRoland Dreier get_random_bytes(&req->param.starting_psn, 4); 663aef9ec39SRoland Dreier req->param.starting_psn &= 0xffffff; 664aef9ec39SRoland Dreier 665aef9ec39SRoland Dreier /* 666aef9ec39SRoland Dreier * Pick some arbitrary defaults here; we could make these 667aef9ec39SRoland Dreier * module parameters if anyone cared about setting them. 668aef9ec39SRoland Dreier */ 669aef9ec39SRoland Dreier req->param.responder_resources = 4; 670aef9ec39SRoland Dreier req->param.remote_cm_response_timeout = 20; 671aef9ec39SRoland Dreier req->param.local_cm_response_timeout = 20; 6727bb312e4SVu Pham req->param.retry_count = target->tl_retry_count; 673aef9ec39SRoland Dreier req->param.rnr_retry_count = 7; 674aef9ec39SRoland Dreier req->param.max_cm_retries = 15; 675aef9ec39SRoland Dreier 676aef9ec39SRoland Dreier req->priv.opcode = SRP_LOGIN_REQ; 677aef9ec39SRoland Dreier req->priv.tag = 0; 67849248644SDavid Dillow req->priv.req_it_iu_len = cpu_to_be32(target->max_iu_len); 679aef9ec39SRoland Dreier req->priv.req_buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT | 680aef9ec39SRoland Dreier SRP_BUF_FORMAT_INDIRECT); 6810c0450dbSRamachandra K /* 6820c0450dbSRamachandra K * In the published SRP specification (draft rev. 16a), the 6830c0450dbSRamachandra K * port identifier format is 8 bytes of ID extension followed 6840c0450dbSRamachandra K * by 8 bytes of GUID. Older drafts put the two halves in the 6850c0450dbSRamachandra K * opposite order, so that the GUID comes first. 6860c0450dbSRamachandra K * 6870c0450dbSRamachandra K * Targets conforming to these obsolete drafts can be 6880c0450dbSRamachandra K * recognized by the I/O Class they report. 6890c0450dbSRamachandra K */ 6900c0450dbSRamachandra K if (target->io_class == SRP_REV10_IB_IO_CLASS) { 6910c0450dbSRamachandra K memcpy(req->priv.initiator_port_id, 69201cb9bcbSIshai Rabinovitz &target->path.sgid.global.interface_id, 8); 6930c0450dbSRamachandra K memcpy(req->priv.initiator_port_id + 8, 69401cb9bcbSIshai Rabinovitz &target->initiator_ext, 8); 6950c0450dbSRamachandra K memcpy(req->priv.target_port_id, &target->ioc_guid, 8); 6960c0450dbSRamachandra K memcpy(req->priv.target_port_id + 8, &target->id_ext, 8); 6970c0450dbSRamachandra K } else { 6980c0450dbSRamachandra K memcpy(req->priv.initiator_port_id, 69901cb9bcbSIshai Rabinovitz &target->initiator_ext, 8); 70001cb9bcbSIshai Rabinovitz memcpy(req->priv.initiator_port_id + 8, 70101cb9bcbSIshai Rabinovitz &target->path.sgid.global.interface_id, 8); 7020c0450dbSRamachandra K memcpy(req->priv.target_port_id, &target->id_ext, 8); 7030c0450dbSRamachandra K memcpy(req->priv.target_port_id + 8, &target->ioc_guid, 8); 7040c0450dbSRamachandra K } 7050c0450dbSRamachandra K 706aef9ec39SRoland Dreier /* 707aef9ec39SRoland Dreier * Topspin/Cisco SRP targets will reject our login unless we 70801cb9bcbSIshai Rabinovitz * zero out the first 8 bytes of our initiator port ID and set 70901cb9bcbSIshai Rabinovitz * the second 8 bytes to the local node GUID. 710aef9ec39SRoland Dreier */ 7115d7cbfd6SRoland Dreier if (srp_target_is_topspin(target)) { 7127aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, target->scsi_host, 7137aa54bd7SDavid Dillow PFX "Topspin/Cisco initiator port ID workaround " 714aef9ec39SRoland Dreier "activated for target GUID %016llx\n", 715aef9ec39SRoland Dreier (unsigned long long) be64_to_cpu(target->ioc_guid)); 716aef9ec39SRoland Dreier memset(req->priv.initiator_port_id, 0, 8); 71701cb9bcbSIshai Rabinovitz memcpy(req->priv.initiator_port_id + 8, 71805321937SGreg Kroah-Hartman &target->srp_host->srp_dev->dev->node_guid, 8); 719aef9ec39SRoland Dreier } 720aef9ec39SRoland Dreier 721aef9ec39SRoland Dreier status = ib_send_cm_req(target->cm_id, &req->param); 722aef9ec39SRoland Dreier 723aef9ec39SRoland Dreier kfree(req); 724aef9ec39SRoland Dreier 725aef9ec39SRoland Dreier return status; 726aef9ec39SRoland Dreier } 727aef9ec39SRoland Dreier 728ef6c49d8SBart Van Assche static bool srp_queue_remove_work(struct srp_target_port *target) 729ef6c49d8SBart Van Assche { 730ef6c49d8SBart Van Assche bool changed = false; 731ef6c49d8SBart Van Assche 732ef6c49d8SBart Van Assche spin_lock_irq(&target->lock); 733ef6c49d8SBart Van Assche if (target->state != SRP_TARGET_REMOVED) { 734ef6c49d8SBart Van Assche target->state = SRP_TARGET_REMOVED; 735ef6c49d8SBart Van Assche changed = true; 736ef6c49d8SBart Van Assche } 737ef6c49d8SBart Van Assche spin_unlock_irq(&target->lock); 738ef6c49d8SBart Van Assche 739ef6c49d8SBart Van Assche if (changed) 740bcc05910SBart Van Assche queue_work(srp_remove_wq, &target->remove_work); 741ef6c49d8SBart Van Assche 742ef6c49d8SBart Van Assche return changed; 743ef6c49d8SBart Van Assche } 744ef6c49d8SBart Van Assche 745294c875aSBart Van Assche static bool srp_change_conn_state(struct srp_target_port *target, 746294c875aSBart Van Assche bool connected) 747294c875aSBart Van Assche { 748294c875aSBart Van Assche bool changed = false; 749294c875aSBart Van Assche 750294c875aSBart Van Assche spin_lock_irq(&target->lock); 751294c875aSBart Van Assche if (target->connected != connected) { 752294c875aSBart Van Assche target->connected = connected; 753294c875aSBart Van Assche changed = true; 754294c875aSBart Van Assche } 755294c875aSBart Van Assche spin_unlock_irq(&target->lock); 756294c875aSBart Van Assche 757294c875aSBart Van Assche return changed; 758294c875aSBart Van Assche } 759294c875aSBart Van Assche 760aef9ec39SRoland Dreier static void srp_disconnect_target(struct srp_target_port *target) 761aef9ec39SRoland Dreier { 762294c875aSBart Van Assche if (srp_change_conn_state(target, false)) { 763aef9ec39SRoland Dreier /* XXX should send SRP_I_LOGOUT request */ 764aef9ec39SRoland Dreier 765e6581056SRoland Dreier if (ib_send_cm_dreq(target->cm_id, NULL, 0)) { 7667aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, target->scsi_host, 7677aa54bd7SDavid Dillow PFX "Sending CM DREQ failed\n"); 768aef9ec39SRoland Dreier } 769294c875aSBart Van Assche } 770294c875aSBart Van Assche } 771aef9ec39SRoland Dreier 7728f26c9ffSDavid Dillow static void srp_free_req_data(struct srp_target_port *target) 7738f26c9ffSDavid Dillow { 7745cfb1782SBart Van Assche struct srp_device *dev = target->srp_host->srp_dev; 7755cfb1782SBart Van Assche struct ib_device *ibdev = dev->dev; 7768f26c9ffSDavid Dillow struct srp_request *req; 7778f26c9ffSDavid Dillow int i; 7788f26c9ffSDavid Dillow 7794d73f95fSBart Van Assche if (!target->req_ring) 7804d73f95fSBart Van Assche return; 7814d73f95fSBart Van Assche 7824d73f95fSBart Van Assche for (i = 0; i < target->req_ring_size; ++i) { 7834d73f95fSBart Van Assche req = &target->req_ring[i]; 7845cfb1782SBart Van Assche if (dev->use_fast_reg) 7855cfb1782SBart Van Assche kfree(req->fr_list); 7865cfb1782SBart Van Assche else 7878f26c9ffSDavid Dillow kfree(req->fmr_list); 7888f26c9ffSDavid Dillow kfree(req->map_page); 789c07d424dSDavid Dillow if (req->indirect_dma_addr) { 790c07d424dSDavid Dillow ib_dma_unmap_single(ibdev, req->indirect_dma_addr, 791c07d424dSDavid Dillow target->indirect_size, 792c07d424dSDavid Dillow DMA_TO_DEVICE); 793c07d424dSDavid Dillow } 794c07d424dSDavid Dillow kfree(req->indirect_desc); 7958f26c9ffSDavid Dillow } 7964d73f95fSBart Van Assche 7974d73f95fSBart Van Assche kfree(target->req_ring); 7984d73f95fSBart Van Assche target->req_ring = NULL; 7998f26c9ffSDavid Dillow } 8008f26c9ffSDavid Dillow 801b81d00bdSBart Van Assche static int srp_alloc_req_data(struct srp_target_port *target) 802b81d00bdSBart Van Assche { 803b81d00bdSBart Van Assche struct srp_device *srp_dev = target->srp_host->srp_dev; 804b81d00bdSBart Van Assche struct ib_device *ibdev = srp_dev->dev; 805b81d00bdSBart Van Assche struct srp_request *req; 8065cfb1782SBart Van Assche void *mr_list; 807b81d00bdSBart Van Assche dma_addr_t dma_addr; 808b81d00bdSBart Van Assche int i, ret = -ENOMEM; 809b81d00bdSBart Van Assche 810b81d00bdSBart Van Assche INIT_LIST_HEAD(&target->free_reqs); 811b81d00bdSBart Van Assche 8124d73f95fSBart Van Assche target->req_ring = kzalloc(target->req_ring_size * 8134d73f95fSBart Van Assche sizeof(*target->req_ring), GFP_KERNEL); 8144d73f95fSBart Van Assche if (!target->req_ring) 8154d73f95fSBart Van Assche goto out; 8164d73f95fSBart Van Assche 8174d73f95fSBart Van Assche for (i = 0; i < target->req_ring_size; ++i) { 818b81d00bdSBart Van Assche req = &target->req_ring[i]; 8195cfb1782SBart Van Assche mr_list = kmalloc(target->cmd_sg_cnt * sizeof(void *), 820b81d00bdSBart Van Assche GFP_KERNEL); 8215cfb1782SBart Van Assche if (!mr_list) 8225cfb1782SBart Van Assche goto out; 8235cfb1782SBart Van Assche if (srp_dev->use_fast_reg) 8245cfb1782SBart Van Assche req->fr_list = mr_list; 8255cfb1782SBart Van Assche else 8265cfb1782SBart Van Assche req->fmr_list = mr_list; 82752ede08fSBart Van Assche req->map_page = kmalloc(srp_dev->max_pages_per_mr * 828d1b4289eSBart Van Assche sizeof(void *), GFP_KERNEL); 8295cfb1782SBart Van Assche if (!req->map_page) 8305cfb1782SBart Van Assche goto out; 831b81d00bdSBart Van Assche req->indirect_desc = kmalloc(target->indirect_size, GFP_KERNEL); 8325cfb1782SBart Van Assche if (!req->indirect_desc) 833b81d00bdSBart Van Assche goto out; 834b81d00bdSBart Van Assche 835b81d00bdSBart Van Assche dma_addr = ib_dma_map_single(ibdev, req->indirect_desc, 836b81d00bdSBart Van Assche target->indirect_size, 837b81d00bdSBart Van Assche DMA_TO_DEVICE); 838b81d00bdSBart Van Assche if (ib_dma_mapping_error(ibdev, dma_addr)) 839b81d00bdSBart Van Assche goto out; 840b81d00bdSBart Van Assche 841b81d00bdSBart Van Assche req->indirect_dma_addr = dma_addr; 842b81d00bdSBart Van Assche req->index = i; 843b81d00bdSBart Van Assche list_add_tail(&req->list, &target->free_reqs); 844b81d00bdSBart Van Assche } 845b81d00bdSBart Van Assche ret = 0; 846b81d00bdSBart Van Assche 847b81d00bdSBart Van Assche out: 848b81d00bdSBart Van Assche return ret; 849b81d00bdSBart Van Assche } 850b81d00bdSBart Van Assche 851683b159aSBart Van Assche /** 852683b159aSBart Van Assche * srp_del_scsi_host_attr() - Remove attributes defined in the host template. 853683b159aSBart Van Assche * @shost: SCSI host whose attributes to remove from sysfs. 854683b159aSBart Van Assche * 855683b159aSBart Van Assche * Note: Any attributes defined in the host template and that did not exist 856683b159aSBart Van Assche * before invocation of this function will be ignored. 857683b159aSBart Van Assche */ 858683b159aSBart Van Assche static void srp_del_scsi_host_attr(struct Scsi_Host *shost) 859683b159aSBart Van Assche { 860683b159aSBart Van Assche struct device_attribute **attr; 861683b159aSBart Van Assche 862683b159aSBart Van Assche for (attr = shost->hostt->shost_attrs; attr && *attr; ++attr) 863683b159aSBart Van Assche device_remove_file(&shost->shost_dev, *attr); 864683b159aSBart Van Assche } 865683b159aSBart Van Assche 866ee12d6a8SBart Van Assche static void srp_remove_target(struct srp_target_port *target) 867ee12d6a8SBart Van Assche { 868ef6c49d8SBart Van Assche WARN_ON_ONCE(target->state != SRP_TARGET_REMOVED); 869ef6c49d8SBart Van Assche 870ee12d6a8SBart Van Assche srp_del_scsi_host_attr(target->scsi_host); 8719dd69a60SBart Van Assche srp_rport_get(target->rport); 872ee12d6a8SBart Van Assche srp_remove_host(target->scsi_host); 873ee12d6a8SBart Van Assche scsi_remove_host(target->scsi_host); 87493079162SBart Van Assche srp_stop_rport_timers(target->rport); 875ef6c49d8SBart Van Assche srp_disconnect_target(target); 876ee12d6a8SBart Van Assche srp_free_target_ib(target); 877c1120f89SBart Van Assche cancel_work_sync(&target->tl_err_work); 8789dd69a60SBart Van Assche srp_rport_put(target->rport); 879ee12d6a8SBart Van Assche srp_free_req_data(target); 88065d7dd2fSVu Pham 88165d7dd2fSVu Pham spin_lock(&target->srp_host->target_lock); 88265d7dd2fSVu Pham list_del(&target->list); 88365d7dd2fSVu Pham spin_unlock(&target->srp_host->target_lock); 88465d7dd2fSVu Pham 885ee12d6a8SBart Van Assche scsi_host_put(target->scsi_host); 886ee12d6a8SBart Van Assche } 887ee12d6a8SBart Van Assche 888c4028958SDavid Howells static void srp_remove_work(struct work_struct *work) 889aef9ec39SRoland Dreier { 890c4028958SDavid Howells struct srp_target_port *target = 891ef6c49d8SBart Van Assche container_of(work, struct srp_target_port, remove_work); 892aef9ec39SRoland Dreier 893ef6c49d8SBart Van Assche WARN_ON_ONCE(target->state != SRP_TARGET_REMOVED); 894aef9ec39SRoland Dreier 89596fc248aSBart Van Assche srp_remove_target(target); 896aef9ec39SRoland Dreier } 897aef9ec39SRoland Dreier 898dc1bdbd9SBart Van Assche static void srp_rport_delete(struct srp_rport *rport) 899dc1bdbd9SBart Van Assche { 900dc1bdbd9SBart Van Assche struct srp_target_port *target = rport->lld_data; 901dc1bdbd9SBart Van Assche 902dc1bdbd9SBart Van Assche srp_queue_remove_work(target); 903dc1bdbd9SBart Van Assche } 904dc1bdbd9SBart Van Assche 905aef9ec39SRoland Dreier static int srp_connect_target(struct srp_target_port *target) 906aef9ec39SRoland Dreier { 9079fe4bcf4SDavid Dillow int retries = 3; 908aef9ec39SRoland Dreier int ret; 909aef9ec39SRoland Dreier 910294c875aSBart Van Assche WARN_ON_ONCE(target->connected); 911294c875aSBart Van Assche 912948d1e88SBart Van Assche target->qp_in_error = false; 913948d1e88SBart Van Assche 914aef9ec39SRoland Dreier ret = srp_lookup_path(target); 915aef9ec39SRoland Dreier if (ret) 916aef9ec39SRoland Dreier return ret; 917aef9ec39SRoland Dreier 918aef9ec39SRoland Dreier while (1) { 919aef9ec39SRoland Dreier init_completion(&target->done); 920aef9ec39SRoland Dreier ret = srp_send_req(target); 921aef9ec39SRoland Dreier if (ret) 922aef9ec39SRoland Dreier return ret; 923a702adceSBart Van Assche ret = wait_for_completion_interruptible(&target->done); 924a702adceSBart Van Assche if (ret < 0) 925a702adceSBart Van Assche return ret; 926aef9ec39SRoland Dreier 927aef9ec39SRoland Dreier /* 928aef9ec39SRoland Dreier * The CM event handling code will set status to 929aef9ec39SRoland Dreier * SRP_PORT_REDIRECT if we get a port redirect REJ 930aef9ec39SRoland Dreier * back, or SRP_DLID_REDIRECT if we get a lid/qp 931aef9ec39SRoland Dreier * redirect REJ back. 932aef9ec39SRoland Dreier */ 933aef9ec39SRoland Dreier switch (target->status) { 934aef9ec39SRoland Dreier case 0: 935294c875aSBart Van Assche srp_change_conn_state(target, true); 936aef9ec39SRoland Dreier return 0; 937aef9ec39SRoland Dreier 938aef9ec39SRoland Dreier case SRP_PORT_REDIRECT: 939aef9ec39SRoland Dreier ret = srp_lookup_path(target); 940aef9ec39SRoland Dreier if (ret) 941aef9ec39SRoland Dreier return ret; 942aef9ec39SRoland Dreier break; 943aef9ec39SRoland Dreier 944aef9ec39SRoland Dreier case SRP_DLID_REDIRECT: 945aef9ec39SRoland Dreier break; 946aef9ec39SRoland Dreier 9479fe4bcf4SDavid Dillow case SRP_STALE_CONN: 9489fe4bcf4SDavid Dillow /* Our current CM id was stale, and is now in timewait. 9499fe4bcf4SDavid Dillow * Try to reconnect with a new one. 9509fe4bcf4SDavid Dillow */ 9519fe4bcf4SDavid Dillow if (!retries-- || srp_new_cm_id(target)) { 9529fe4bcf4SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX 9539fe4bcf4SDavid Dillow "giving up on stale connection\n"); 9549fe4bcf4SDavid Dillow target->status = -ECONNRESET; 9559fe4bcf4SDavid Dillow return target->status; 9569fe4bcf4SDavid Dillow } 9579fe4bcf4SDavid Dillow 9589fe4bcf4SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX 9599fe4bcf4SDavid Dillow "retrying stale connection\n"); 9609fe4bcf4SDavid Dillow break; 9619fe4bcf4SDavid Dillow 962aef9ec39SRoland Dreier default: 963aef9ec39SRoland Dreier return target->status; 964aef9ec39SRoland Dreier } 965aef9ec39SRoland Dreier } 966aef9ec39SRoland Dreier } 967aef9ec39SRoland Dreier 9685cfb1782SBart Van Assche static int srp_inv_rkey(struct srp_target_port *target, u32 rkey) 9695cfb1782SBart Van Assche { 9705cfb1782SBart Van Assche struct ib_send_wr *bad_wr; 9715cfb1782SBart Van Assche struct ib_send_wr wr = { 9725cfb1782SBart Van Assche .opcode = IB_WR_LOCAL_INV, 9735cfb1782SBart Van Assche .wr_id = LOCAL_INV_WR_ID_MASK, 9745cfb1782SBart Van Assche .next = NULL, 9755cfb1782SBart Van Assche .num_sge = 0, 9765cfb1782SBart Van Assche .send_flags = 0, 9775cfb1782SBart Van Assche .ex.invalidate_rkey = rkey, 9785cfb1782SBart Van Assche }; 9795cfb1782SBart Van Assche 9805cfb1782SBart Van Assche return ib_post_send(target->qp, &wr, &bad_wr); 9815cfb1782SBart Van Assche } 9825cfb1782SBart Van Assche 983d945e1dfSRoland Dreier static void srp_unmap_data(struct scsi_cmnd *scmnd, 984d945e1dfSRoland Dreier struct srp_target_port *target, 985d945e1dfSRoland Dreier struct srp_request *req) 986d945e1dfSRoland Dreier { 9875cfb1782SBart Van Assche struct srp_device *dev = target->srp_host->srp_dev; 9885cfb1782SBart Van Assche struct ib_device *ibdev = dev->dev; 9895cfb1782SBart Van Assche int i, res; 9908f26c9ffSDavid Dillow 991bb350d1dSFUJITA Tomonori if (!scsi_sglist(scmnd) || 992d945e1dfSRoland Dreier (scmnd->sc_data_direction != DMA_TO_DEVICE && 993d945e1dfSRoland Dreier scmnd->sc_data_direction != DMA_FROM_DEVICE)) 994d945e1dfSRoland Dreier return; 995d945e1dfSRoland Dreier 9965cfb1782SBart Van Assche if (dev->use_fast_reg) { 9975cfb1782SBart Van Assche struct srp_fr_desc **pfr; 9985cfb1782SBart Van Assche 9995cfb1782SBart Van Assche for (i = req->nmdesc, pfr = req->fr_list; i > 0; i--, pfr++) { 10005cfb1782SBart Van Assche res = srp_inv_rkey(target, (*pfr)->mr->rkey); 10015cfb1782SBart Van Assche if (res < 0) { 10025cfb1782SBart Van Assche shost_printk(KERN_ERR, target->scsi_host, PFX 10035cfb1782SBart Van Assche "Queueing INV WR for rkey %#x failed (%d)\n", 10045cfb1782SBart Van Assche (*pfr)->mr->rkey, res); 10055cfb1782SBart Van Assche queue_work(system_long_wq, 10065cfb1782SBart Van Assche &target->tl_err_work); 10075cfb1782SBart Van Assche } 10085cfb1782SBart Van Assche } 10095cfb1782SBart Van Assche if (req->nmdesc) 10105cfb1782SBart Van Assche srp_fr_pool_put(target->fr_pool, req->fr_list, 10115cfb1782SBart Van Assche req->nmdesc); 10125cfb1782SBart Van Assche } else { 10135cfb1782SBart Van Assche struct ib_pool_fmr **pfmr; 10145cfb1782SBart Van Assche 10155cfb1782SBart Van Assche for (i = req->nmdesc, pfmr = req->fmr_list; i > 0; i--, pfmr++) 10165cfb1782SBart Van Assche ib_fmr_pool_unmap(*pfmr); 10175cfb1782SBart Van Assche } 1018f5358a17SRoland Dreier 10198f26c9ffSDavid Dillow ib_dma_unmap_sg(ibdev, scsi_sglist(scmnd), scsi_sg_count(scmnd), 10208f26c9ffSDavid Dillow scmnd->sc_data_direction); 1021d945e1dfSRoland Dreier } 1022d945e1dfSRoland Dreier 102322032991SBart Van Assche /** 102422032991SBart Van Assche * srp_claim_req - Take ownership of the scmnd associated with a request. 102522032991SBart Van Assche * @target: SRP target port. 102622032991SBart Van Assche * @req: SRP request. 1027b3fe628dSBart Van Assche * @sdev: If not NULL, only take ownership for this SCSI device. 102822032991SBart Van Assche * @scmnd: If NULL, take ownership of @req->scmnd. If not NULL, only take 102922032991SBart Van Assche * ownership of @req->scmnd if it equals @scmnd. 103022032991SBart Van Assche * 103122032991SBart Van Assche * Return value: 103222032991SBart Van Assche * Either NULL or a pointer to the SCSI command the caller became owner of. 103322032991SBart Van Assche */ 103422032991SBart Van Assche static struct scsi_cmnd *srp_claim_req(struct srp_target_port *target, 103522032991SBart Van Assche struct srp_request *req, 1036b3fe628dSBart Van Assche struct scsi_device *sdev, 103722032991SBart Van Assche struct scsi_cmnd *scmnd) 1038526b4caaSIshai Rabinovitz { 103994a9174cSBart Van Assche unsigned long flags; 104094a9174cSBart Van Assche 104122032991SBart Van Assche spin_lock_irqsave(&target->lock, flags); 1042b3fe628dSBart Van Assche if (req->scmnd && 1043b3fe628dSBart Van Assche (!sdev || req->scmnd->device == sdev) && 1044b3fe628dSBart Van Assche (!scmnd || req->scmnd == scmnd)) { 104522032991SBart Van Assche scmnd = req->scmnd; 104622032991SBart Van Assche req->scmnd = NULL; 104722032991SBart Van Assche } else { 104822032991SBart Van Assche scmnd = NULL; 104922032991SBart Van Assche } 105022032991SBart Van Assche spin_unlock_irqrestore(&target->lock, flags); 105122032991SBart Van Assche 105222032991SBart Van Assche return scmnd; 105322032991SBart Van Assche } 105422032991SBart Van Assche 105522032991SBart Van Assche /** 105622032991SBart Van Assche * srp_free_req() - Unmap data and add request to the free request list. 1057af24663bSBart Van Assche * @target: SRP target port. 1058af24663bSBart Van Assche * @req: Request to be freed. 1059af24663bSBart Van Assche * @scmnd: SCSI command associated with @req. 1060af24663bSBart Van Assche * @req_lim_delta: Amount to be added to @target->req_lim. 106122032991SBart Van Assche */ 106222032991SBart Van Assche static void srp_free_req(struct srp_target_port *target, 106322032991SBart Van Assche struct srp_request *req, struct scsi_cmnd *scmnd, 106422032991SBart Van Assche s32 req_lim_delta) 106522032991SBart Van Assche { 106622032991SBart Van Assche unsigned long flags; 106722032991SBart Van Assche 106822032991SBart Van Assche srp_unmap_data(scmnd, target, req); 106922032991SBart Van Assche 1070e9684678SBart Van Assche spin_lock_irqsave(&target->lock, flags); 107194a9174cSBart Van Assche target->req_lim += req_lim_delta; 1072536ae14eSBart Van Assche list_add_tail(&req->list, &target->free_reqs); 1073e9684678SBart Van Assche spin_unlock_irqrestore(&target->lock, flags); 1074526b4caaSIshai Rabinovitz } 1075526b4caaSIshai Rabinovitz 1076ed9b2264SBart Van Assche static void srp_finish_req(struct srp_target_port *target, 1077b3fe628dSBart Van Assche struct srp_request *req, struct scsi_device *sdev, 1078b3fe628dSBart Van Assche int result) 1079526b4caaSIshai Rabinovitz { 1080b3fe628dSBart Van Assche struct scsi_cmnd *scmnd = srp_claim_req(target, req, sdev, NULL); 108122032991SBart Van Assche 108222032991SBart Van Assche if (scmnd) { 10839b796d06SBart Van Assche srp_free_req(target, req, scmnd, 0); 1084ed9b2264SBart Van Assche scmnd->result = result; 108522032991SBart Van Assche scmnd->scsi_done(scmnd); 108622032991SBart Van Assche } 1087526b4caaSIshai Rabinovitz } 1088526b4caaSIshai Rabinovitz 1089ed9b2264SBart Van Assche static void srp_terminate_io(struct srp_rport *rport) 1090aef9ec39SRoland Dreier { 1091ed9b2264SBart Van Assche struct srp_target_port *target = rport->lld_data; 1092b3fe628dSBart Van Assche struct Scsi_Host *shost = target->scsi_host; 1093b3fe628dSBart Van Assche struct scsi_device *sdev; 1094ed9b2264SBart Van Assche int i; 1095aef9ec39SRoland Dreier 1096b3fe628dSBart Van Assche /* 1097b3fe628dSBart Van Assche * Invoking srp_terminate_io() while srp_queuecommand() is running 1098b3fe628dSBart Van Assche * is not safe. Hence the warning statement below. 1099b3fe628dSBart Van Assche */ 1100b3fe628dSBart Van Assche shost_for_each_device(sdev, shost) 1101b3fe628dSBart Van Assche WARN_ON_ONCE(sdev->request_queue->request_fn_active); 1102b3fe628dSBart Van Assche 11034d73f95fSBart Van Assche for (i = 0; i < target->req_ring_size; ++i) { 1104ed9b2264SBart Van Assche struct srp_request *req = &target->req_ring[i]; 1105b3fe628dSBart Van Assche srp_finish_req(target, req, NULL, DID_TRANSPORT_FAILFAST << 16); 1106ed9b2264SBart Van Assche } 1107ed9b2264SBart Van Assche } 1108ed9b2264SBart Van Assche 1109ed9b2264SBart Van Assche /* 1110ed9b2264SBart Van Assche * It is up to the caller to ensure that srp_rport_reconnect() calls are 1111ed9b2264SBart Van Assche * serialized and that no concurrent srp_queuecommand(), srp_abort(), 1112ed9b2264SBart Van Assche * srp_reset_device() or srp_reset_host() calls will occur while this function 1113ed9b2264SBart Van Assche * is in progress. One way to realize that is not to call this function 1114ed9b2264SBart Van Assche * directly but to call srp_reconnect_rport() instead since that last function 1115ed9b2264SBart Van Assche * serializes calls of this function via rport->mutex and also blocks 1116ed9b2264SBart Van Assche * srp_queuecommand() calls before invoking this function. 1117ed9b2264SBart Van Assche */ 1118ed9b2264SBart Van Assche static int srp_rport_reconnect(struct srp_rport *rport) 1119ed9b2264SBart Van Assche { 1120ed9b2264SBart Van Assche struct srp_target_port *target = rport->lld_data; 1121ed9b2264SBart Van Assche int i, ret; 112209be70a2SBart Van Assche 1123aef9ec39SRoland Dreier srp_disconnect_target(target); 1124aef9ec39SRoland Dreier /* 1125c7c4e7ffSBart Van Assche * Now get a new local CM ID so that we avoid confusing the target in 1126c7c4e7ffSBart Van Assche * case things are really fouled up. Doing so also ensures that all CM 1127c7c4e7ffSBart Van Assche * callbacks will have finished before a new QP is allocated. 1128aef9ec39SRoland Dreier */ 11299fe4bcf4SDavid Dillow ret = srp_new_cm_id(target); 1130aef9ec39SRoland Dreier 11314d73f95fSBart Van Assche for (i = 0; i < target->req_ring_size; ++i) { 1132536ae14eSBart Van Assche struct srp_request *req = &target->req_ring[i]; 1133b3fe628dSBart Van Assche srp_finish_req(target, req, NULL, DID_RESET << 16); 1134536ae14eSBart Van Assche } 1135aef9ec39SRoland Dreier 11365cfb1782SBart Van Assche /* 11375cfb1782SBart Van Assche * Whether or not creating a new CM ID succeeded, create a new 11385cfb1782SBart Van Assche * QP. This guarantees that all callback functions for the old QP have 11395cfb1782SBart Van Assche * finished before any send requests are posted on the new QP. 11405cfb1782SBart Van Assche */ 11415cfb1782SBart Van Assche ret += srp_create_target_ib(target); 11425cfb1782SBart Van Assche 1143536ae14eSBart Van Assche INIT_LIST_HEAD(&target->free_tx); 11444d73f95fSBart Van Assche for (i = 0; i < target->queue_size; ++i) 1145536ae14eSBart Van Assche list_add(&target->tx_ring[i]->list, &target->free_tx); 1146aef9ec39SRoland Dreier 1147c7c4e7ffSBart Van Assche if (ret == 0) 1148aef9ec39SRoland Dreier ret = srp_connect_target(target); 114909be70a2SBart Van Assche 1150ed9b2264SBart Van Assche if (ret == 0) 1151ed9b2264SBart Van Assche shost_printk(KERN_INFO, target->scsi_host, 1152ed9b2264SBart Van Assche PFX "reconnect succeeded\n"); 1153aef9ec39SRoland Dreier 1154aef9ec39SRoland Dreier return ret; 1155aef9ec39SRoland Dreier } 1156aef9ec39SRoland Dreier 11578f26c9ffSDavid Dillow static void srp_map_desc(struct srp_map_state *state, dma_addr_t dma_addr, 11588f26c9ffSDavid Dillow unsigned int dma_len, u32 rkey) 1159f5358a17SRoland Dreier { 11608f26c9ffSDavid Dillow struct srp_direct_buf *desc = state->desc; 11618f26c9ffSDavid Dillow 11628f26c9ffSDavid Dillow desc->va = cpu_to_be64(dma_addr); 11638f26c9ffSDavid Dillow desc->key = cpu_to_be32(rkey); 11648f26c9ffSDavid Dillow desc->len = cpu_to_be32(dma_len); 11658f26c9ffSDavid Dillow 11668f26c9ffSDavid Dillow state->total_len += dma_len; 11678f26c9ffSDavid Dillow state->desc++; 11688f26c9ffSDavid Dillow state->ndesc++; 11698f26c9ffSDavid Dillow } 11708f26c9ffSDavid Dillow 11718f26c9ffSDavid Dillow static int srp_map_finish_fmr(struct srp_map_state *state, 11728f26c9ffSDavid Dillow struct srp_target_port *target) 11738f26c9ffSDavid Dillow { 11748f26c9ffSDavid Dillow struct ib_pool_fmr *fmr; 1175f5358a17SRoland Dreier u64 io_addr = 0; 11768f26c9ffSDavid Dillow 1177d1b4289eSBart Van Assche fmr = ib_fmr_pool_map_phys(target->fmr_pool, state->pages, 11788f26c9ffSDavid Dillow state->npages, io_addr); 11798f26c9ffSDavid Dillow if (IS_ERR(fmr)) 11808f26c9ffSDavid Dillow return PTR_ERR(fmr); 11818f26c9ffSDavid Dillow 11828f26c9ffSDavid Dillow *state->next_fmr++ = fmr; 118352ede08fSBart Van Assche state->nmdesc++; 11848f26c9ffSDavid Dillow 118552ede08fSBart Van Assche srp_map_desc(state, 0, state->dma_len, fmr->fmr->rkey); 1186539dde6fSBart Van Assche 11878f26c9ffSDavid Dillow return 0; 11888f26c9ffSDavid Dillow } 11898f26c9ffSDavid Dillow 11905cfb1782SBart Van Assche static int srp_map_finish_fr(struct srp_map_state *state, 11915cfb1782SBart Van Assche struct srp_target_port *target) 11925cfb1782SBart Van Assche { 11935cfb1782SBart Van Assche struct srp_device *dev = target->srp_host->srp_dev; 11945cfb1782SBart Van Assche struct ib_send_wr *bad_wr; 11955cfb1782SBart Van Assche struct ib_send_wr wr; 11965cfb1782SBart Van Assche struct srp_fr_desc *desc; 11975cfb1782SBart Van Assche u32 rkey; 11985cfb1782SBart Van Assche 11995cfb1782SBart Van Assche desc = srp_fr_pool_get(target->fr_pool); 12005cfb1782SBart Van Assche if (!desc) 12015cfb1782SBart Van Assche return -ENOMEM; 12025cfb1782SBart Van Assche 12035cfb1782SBart Van Assche rkey = ib_inc_rkey(desc->mr->rkey); 12045cfb1782SBart Van Assche ib_update_fast_reg_key(desc->mr, rkey); 12055cfb1782SBart Van Assche 12065cfb1782SBart Van Assche memcpy(desc->frpl->page_list, state->pages, 12075cfb1782SBart Van Assche sizeof(state->pages[0]) * state->npages); 12085cfb1782SBart Van Assche 12095cfb1782SBart Van Assche memset(&wr, 0, sizeof(wr)); 12105cfb1782SBart Van Assche wr.opcode = IB_WR_FAST_REG_MR; 12115cfb1782SBart Van Assche wr.wr_id = FAST_REG_WR_ID_MASK; 12125cfb1782SBart Van Assche wr.wr.fast_reg.iova_start = state->base_dma_addr; 12135cfb1782SBart Van Assche wr.wr.fast_reg.page_list = desc->frpl; 12145cfb1782SBart Van Assche wr.wr.fast_reg.page_list_len = state->npages; 12155cfb1782SBart Van Assche wr.wr.fast_reg.page_shift = ilog2(dev->mr_page_size); 12165cfb1782SBart Van Assche wr.wr.fast_reg.length = state->dma_len; 12175cfb1782SBart Van Assche wr.wr.fast_reg.access_flags = (IB_ACCESS_LOCAL_WRITE | 12185cfb1782SBart Van Assche IB_ACCESS_REMOTE_READ | 12195cfb1782SBart Van Assche IB_ACCESS_REMOTE_WRITE); 12205cfb1782SBart Van Assche wr.wr.fast_reg.rkey = desc->mr->lkey; 12215cfb1782SBart Van Assche 12225cfb1782SBart Van Assche *state->next_fr++ = desc; 12235cfb1782SBart Van Assche state->nmdesc++; 12245cfb1782SBart Van Assche 12255cfb1782SBart Van Assche srp_map_desc(state, state->base_dma_addr, state->dma_len, 12265cfb1782SBart Van Assche desc->mr->rkey); 12275cfb1782SBart Van Assche 12285cfb1782SBart Van Assche return ib_post_send(target->qp, &wr, &bad_wr); 12295cfb1782SBart Van Assche } 12305cfb1782SBart Van Assche 1231539dde6fSBart Van Assche static int srp_finish_mapping(struct srp_map_state *state, 1232539dde6fSBart Van Assche struct srp_target_port *target) 1233539dde6fSBart Van Assche { 1234539dde6fSBart Van Assche int ret = 0; 1235539dde6fSBart Van Assche 1236539dde6fSBart Van Assche if (state->npages == 0) 1237539dde6fSBart Van Assche return 0; 1238539dde6fSBart Van Assche 1239b1b8854dSBart Van Assche if (state->npages == 1 && !register_always) 124052ede08fSBart Van Assche srp_map_desc(state, state->base_dma_addr, state->dma_len, 1241539dde6fSBart Van Assche target->rkey); 1242539dde6fSBart Van Assche else 12435cfb1782SBart Van Assche ret = target->srp_host->srp_dev->use_fast_reg ? 12445cfb1782SBart Van Assche srp_map_finish_fr(state, target) : 12455cfb1782SBart Van Assche srp_map_finish_fmr(state, target); 1246539dde6fSBart Van Assche 1247539dde6fSBart Van Assche if (ret == 0) { 1248539dde6fSBart Van Assche state->npages = 0; 124952ede08fSBart Van Assche state->dma_len = 0; 1250539dde6fSBart Van Assche } 1251539dde6fSBart Van Assche 1252539dde6fSBart Van Assche return ret; 1253539dde6fSBart Van Assche } 1254539dde6fSBart Van Assche 12558f26c9ffSDavid Dillow static void srp_map_update_start(struct srp_map_state *state, 12568f26c9ffSDavid Dillow struct scatterlist *sg, int sg_index, 12578f26c9ffSDavid Dillow dma_addr_t dma_addr) 12588f26c9ffSDavid Dillow { 12598f26c9ffSDavid Dillow state->unmapped_sg = sg; 12608f26c9ffSDavid Dillow state->unmapped_index = sg_index; 12618f26c9ffSDavid Dillow state->unmapped_addr = dma_addr; 12628f26c9ffSDavid Dillow } 12638f26c9ffSDavid Dillow 12648f26c9ffSDavid Dillow static int srp_map_sg_entry(struct srp_map_state *state, 12658f26c9ffSDavid Dillow struct srp_target_port *target, 12668f26c9ffSDavid Dillow struct scatterlist *sg, int sg_index, 12675cfb1782SBart Van Assche bool use_mr) 12688f26c9ffSDavid Dillow { 126905321937SGreg Kroah-Hartman struct srp_device *dev = target->srp_host->srp_dev; 127085507bccSRalph Campbell struct ib_device *ibdev = dev->dev; 12718f26c9ffSDavid Dillow dma_addr_t dma_addr = ib_sg_dma_address(ibdev, sg); 1272bb350d1dSFUJITA Tomonori unsigned int dma_len = ib_sg_dma_len(ibdev, sg); 12738f26c9ffSDavid Dillow unsigned int len; 12748f26c9ffSDavid Dillow int ret; 127585507bccSRalph Campbell 12768f26c9ffSDavid Dillow if (!dma_len) 12778f26c9ffSDavid Dillow return 0; 12788f26c9ffSDavid Dillow 12795cfb1782SBart Van Assche if (!use_mr) { 12805cfb1782SBart Van Assche /* 12815cfb1782SBart Van Assche * Once we're in direct map mode for a request, we don't 12825cfb1782SBart Van Assche * go back to FMR or FR mode, so no need to update anything 12838f26c9ffSDavid Dillow * other than the descriptor. 12848f26c9ffSDavid Dillow */ 12858f26c9ffSDavid Dillow srp_map_desc(state, dma_addr, dma_len, target->rkey); 12868f26c9ffSDavid Dillow return 0; 1287f5358a17SRoland Dreier } 1288f5358a17SRoland Dreier 12895cfb1782SBart Van Assche /* 12905cfb1782SBart Van Assche * Since not all RDMA HW drivers support non-zero page offsets for 12915cfb1782SBart Van Assche * FMR, if we start at an offset into a page, don't merge into the 12925cfb1782SBart Van Assche * current FMR mapping. Finish it out, and use the kernel's MR for 12935cfb1782SBart Van Assche * this sg entry. 12948f26c9ffSDavid Dillow */ 12955cfb1782SBart Van Assche if ((!dev->use_fast_reg && dma_addr & ~dev->mr_page_mask) || 12965cfb1782SBart Van Assche dma_len > dev->mr_max_size) { 1297539dde6fSBart Van Assche ret = srp_finish_mapping(state, target); 12988f26c9ffSDavid Dillow if (ret) 12998f26c9ffSDavid Dillow return ret; 13008f26c9ffSDavid Dillow 13018f26c9ffSDavid Dillow srp_map_desc(state, dma_addr, dma_len, target->rkey); 13028f26c9ffSDavid Dillow srp_map_update_start(state, NULL, 0, 0); 13038f26c9ffSDavid Dillow return 0; 1304f5358a17SRoland Dreier } 1305f5358a17SRoland Dreier 13065cfb1782SBart Van Assche /* 13075cfb1782SBart Van Assche * If this is the first sg that will be mapped via FMR or via FR, save 13085cfb1782SBart Van Assche * our position. We need to know the first unmapped entry, its index, 13095cfb1782SBart Van Assche * and the first unmapped address within that entry to be able to 13105cfb1782SBart Van Assche * restart mapping after an error. 13118f26c9ffSDavid Dillow */ 13128f26c9ffSDavid Dillow if (!state->unmapped_sg) 13138f26c9ffSDavid Dillow srp_map_update_start(state, sg, sg_index, dma_addr); 1314f5358a17SRoland Dreier 13158f26c9ffSDavid Dillow while (dma_len) { 13165cfb1782SBart Van Assche unsigned offset = dma_addr & ~dev->mr_page_mask; 13175cfb1782SBart Van Assche if (state->npages == dev->max_pages_per_mr || offset != 0) { 1318539dde6fSBart Van Assche ret = srp_finish_mapping(state, target); 13198f26c9ffSDavid Dillow if (ret) 13208f26c9ffSDavid Dillow return ret; 1321f5358a17SRoland Dreier 13228f26c9ffSDavid Dillow srp_map_update_start(state, sg, sg_index, dma_addr); 132385507bccSRalph Campbell } 1324f5358a17SRoland Dreier 13255cfb1782SBart Van Assche len = min_t(unsigned int, dma_len, dev->mr_page_size - offset); 13268f26c9ffSDavid Dillow 13278f26c9ffSDavid Dillow if (!state->npages) 13288f26c9ffSDavid Dillow state->base_dma_addr = dma_addr; 13295cfb1782SBart Van Assche state->pages[state->npages++] = dma_addr & dev->mr_page_mask; 133052ede08fSBart Van Assche state->dma_len += len; 13318f26c9ffSDavid Dillow dma_addr += len; 13328f26c9ffSDavid Dillow dma_len -= len; 1333f5358a17SRoland Dreier } 1334f5358a17SRoland Dreier 13355cfb1782SBart Van Assche /* 13365cfb1782SBart Van Assche * If the last entry of the MR wasn't a full page, then we need to 13378f26c9ffSDavid Dillow * close it out and start a new one -- we can only merge at page 13388f26c9ffSDavid Dillow * boundries. 13398f26c9ffSDavid Dillow */ 1340f5358a17SRoland Dreier ret = 0; 134152ede08fSBart Van Assche if (len != dev->mr_page_size) { 1342539dde6fSBart Van Assche ret = srp_finish_mapping(state, target); 13438f26c9ffSDavid Dillow if (!ret) 13448f26c9ffSDavid Dillow srp_map_update_start(state, NULL, 0, 0); 13458f26c9ffSDavid Dillow } 1346f5358a17SRoland Dreier return ret; 1347f5358a17SRoland Dreier } 1348f5358a17SRoland Dreier 13495cfb1782SBart Van Assche static int srp_map_sg(struct srp_map_state *state, 135076bc1e1dSBart Van Assche struct srp_target_port *target, struct srp_request *req, 135176bc1e1dSBart Van Assche struct scatterlist *scat, int count) 135276bc1e1dSBart Van Assche { 135376bc1e1dSBart Van Assche struct srp_device *dev = target->srp_host->srp_dev; 135476bc1e1dSBart Van Assche struct ib_device *ibdev = dev->dev; 135576bc1e1dSBart Van Assche struct scatterlist *sg; 13565cfb1782SBart Van Assche int i; 13575cfb1782SBart Van Assche bool use_mr; 135876bc1e1dSBart Van Assche 135976bc1e1dSBart Van Assche state->desc = req->indirect_desc; 136076bc1e1dSBart Van Assche state->pages = req->map_page; 13615cfb1782SBart Van Assche if (dev->use_fast_reg) { 13625cfb1782SBart Van Assche state->next_fr = req->fr_list; 13635cfb1782SBart Van Assche use_mr = !!target->fr_pool; 13645cfb1782SBart Van Assche } else { 136576bc1e1dSBart Van Assche state->next_fmr = req->fmr_list; 13665cfb1782SBart Van Assche use_mr = !!target->fmr_pool; 13675cfb1782SBart Van Assche } 136876bc1e1dSBart Van Assche 136976bc1e1dSBart Van Assche for_each_sg(scat, sg, count, i) { 13705cfb1782SBart Van Assche if (srp_map_sg_entry(state, target, sg, i, use_mr)) { 13715cfb1782SBart Van Assche /* 13725cfb1782SBart Van Assche * Memory registration failed, so backtrack to the 13735cfb1782SBart Van Assche * first unmapped entry and continue on without using 13745cfb1782SBart Van Assche * memory registration. 137576bc1e1dSBart Van Assche */ 137676bc1e1dSBart Van Assche dma_addr_t dma_addr; 137776bc1e1dSBart Van Assche unsigned int dma_len; 137876bc1e1dSBart Van Assche 137976bc1e1dSBart Van Assche backtrack: 138076bc1e1dSBart Van Assche sg = state->unmapped_sg; 138176bc1e1dSBart Van Assche i = state->unmapped_index; 138276bc1e1dSBart Van Assche 138376bc1e1dSBart Van Assche dma_addr = ib_sg_dma_address(ibdev, sg); 138476bc1e1dSBart Van Assche dma_len = ib_sg_dma_len(ibdev, sg); 138576bc1e1dSBart Van Assche dma_len -= (state->unmapped_addr - dma_addr); 138676bc1e1dSBart Van Assche dma_addr = state->unmapped_addr; 13875cfb1782SBart Van Assche use_mr = false; 138876bc1e1dSBart Van Assche srp_map_desc(state, dma_addr, dma_len, target->rkey); 138976bc1e1dSBart Van Assche } 139076bc1e1dSBart Van Assche } 139176bc1e1dSBart Van Assche 13925cfb1782SBart Van Assche if (use_mr && srp_finish_mapping(state, target)) 139376bc1e1dSBart Van Assche goto backtrack; 139476bc1e1dSBart Van Assche 139552ede08fSBart Van Assche req->nmdesc = state->nmdesc; 13965cfb1782SBart Van Assche 13975cfb1782SBart Van Assche return 0; 139876bc1e1dSBart Van Assche } 139976bc1e1dSBart Van Assche 1400aef9ec39SRoland Dreier static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target, 1401aef9ec39SRoland Dreier struct srp_request *req) 1402aef9ec39SRoland Dreier { 140376bc1e1dSBart Van Assche struct scatterlist *scat; 1404aef9ec39SRoland Dreier struct srp_cmd *cmd = req->cmd->buf; 140576bc1e1dSBart Van Assche int len, nents, count; 140685507bccSRalph Campbell struct srp_device *dev; 140785507bccSRalph Campbell struct ib_device *ibdev; 14088f26c9ffSDavid Dillow struct srp_map_state state; 14098f26c9ffSDavid Dillow struct srp_indirect_buf *indirect_hdr; 14108f26c9ffSDavid Dillow u32 table_len; 14118f26c9ffSDavid Dillow u8 fmt; 1412aef9ec39SRoland Dreier 1413bb350d1dSFUJITA Tomonori if (!scsi_sglist(scmnd) || scmnd->sc_data_direction == DMA_NONE) 1414aef9ec39SRoland Dreier return sizeof (struct srp_cmd); 1415aef9ec39SRoland Dreier 1416aef9ec39SRoland Dreier if (scmnd->sc_data_direction != DMA_FROM_DEVICE && 1417aef9ec39SRoland Dreier scmnd->sc_data_direction != DMA_TO_DEVICE) { 14187aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 14197aa54bd7SDavid Dillow PFX "Unhandled data direction %d\n", 1420aef9ec39SRoland Dreier scmnd->sc_data_direction); 1421aef9ec39SRoland Dreier return -EINVAL; 1422aef9ec39SRoland Dreier } 1423aef9ec39SRoland Dreier 1424bb350d1dSFUJITA Tomonori nents = scsi_sg_count(scmnd); 1425bb350d1dSFUJITA Tomonori scat = scsi_sglist(scmnd); 1426aef9ec39SRoland Dreier 142705321937SGreg Kroah-Hartman dev = target->srp_host->srp_dev; 142885507bccSRalph Campbell ibdev = dev->dev; 142985507bccSRalph Campbell 143085507bccSRalph Campbell count = ib_dma_map_sg(ibdev, scat, nents, scmnd->sc_data_direction); 14318f26c9ffSDavid Dillow if (unlikely(count == 0)) 14328f26c9ffSDavid Dillow return -EIO; 1433aef9ec39SRoland Dreier 1434aef9ec39SRoland Dreier fmt = SRP_DATA_DESC_DIRECT; 1435f5358a17SRoland Dreier len = sizeof (struct srp_cmd) + sizeof (struct srp_direct_buf); 1436f5358a17SRoland Dreier 1437b1b8854dSBart Van Assche if (count == 1 && !register_always) { 1438f5358a17SRoland Dreier /* 1439f5358a17SRoland Dreier * The midlayer only generated a single gather/scatter 1440f5358a17SRoland Dreier * entry, or DMA mapping coalesced everything to a 1441f5358a17SRoland Dreier * single entry. So a direct descriptor along with 1442f5358a17SRoland Dreier * the DMA MR suffices. 1443f5358a17SRoland Dreier */ 1444f5358a17SRoland Dreier struct srp_direct_buf *buf = (void *) cmd->add_data; 1445aef9ec39SRoland Dreier 144685507bccSRalph Campbell buf->va = cpu_to_be64(ib_sg_dma_address(ibdev, scat)); 14479af76271SDavid Dillow buf->key = cpu_to_be32(target->rkey); 144885507bccSRalph Campbell buf->len = cpu_to_be32(ib_sg_dma_len(ibdev, scat)); 14498f26c9ffSDavid Dillow 145052ede08fSBart Van Assche req->nmdesc = 0; 14518f26c9ffSDavid Dillow goto map_complete; 14528f26c9ffSDavid Dillow } 14538f26c9ffSDavid Dillow 14545cfb1782SBart Van Assche /* 14555cfb1782SBart Van Assche * We have more than one scatter/gather entry, so build our indirect 14565cfb1782SBart Van Assche * descriptor table, trying to merge as many entries as we can. 1457f5358a17SRoland Dreier */ 14588f26c9ffSDavid Dillow indirect_hdr = (void *) cmd->add_data; 14598f26c9ffSDavid Dillow 1460c07d424dSDavid Dillow ib_dma_sync_single_for_cpu(ibdev, req->indirect_dma_addr, 1461c07d424dSDavid Dillow target->indirect_size, DMA_TO_DEVICE); 1462c07d424dSDavid Dillow 14638f26c9ffSDavid Dillow memset(&state, 0, sizeof(state)); 14645cfb1782SBart Van Assche srp_map_sg(&state, target, req, scat, count); 14658f26c9ffSDavid Dillow 1466c07d424dSDavid Dillow /* We've mapped the request, now pull as much of the indirect 1467c07d424dSDavid Dillow * descriptor table as we can into the command buffer. If this 1468c07d424dSDavid Dillow * target is not using an external indirect table, we are 1469c07d424dSDavid Dillow * guaranteed to fit into the command, as the SCSI layer won't 1470c07d424dSDavid Dillow * give us more S/G entries than we allow. 14718f26c9ffSDavid Dillow */ 14728f26c9ffSDavid Dillow if (state.ndesc == 1) { 14735cfb1782SBart Van Assche /* 14745cfb1782SBart Van Assche * Memory registration collapsed the sg-list into one entry, 14758f26c9ffSDavid Dillow * so use a direct descriptor. 14768f26c9ffSDavid Dillow */ 14778f26c9ffSDavid Dillow struct srp_direct_buf *buf = (void *) cmd->add_data; 14788f26c9ffSDavid Dillow 1479c07d424dSDavid Dillow *buf = req->indirect_desc[0]; 14808f26c9ffSDavid Dillow goto map_complete; 14818f26c9ffSDavid Dillow } 14828f26c9ffSDavid Dillow 1483c07d424dSDavid Dillow if (unlikely(target->cmd_sg_cnt < state.ndesc && 1484c07d424dSDavid Dillow !target->allow_ext_sg)) { 1485c07d424dSDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 1486c07d424dSDavid Dillow "Could not fit S/G list into SRP_CMD\n"); 1487c07d424dSDavid Dillow return -EIO; 1488c07d424dSDavid Dillow } 1489c07d424dSDavid Dillow 1490c07d424dSDavid Dillow count = min(state.ndesc, target->cmd_sg_cnt); 14918f26c9ffSDavid Dillow table_len = state.ndesc * sizeof (struct srp_direct_buf); 1492aef9ec39SRoland Dreier 1493aef9ec39SRoland Dreier fmt = SRP_DATA_DESC_INDIRECT; 14948f26c9ffSDavid Dillow len = sizeof(struct srp_cmd) + sizeof (struct srp_indirect_buf); 1495c07d424dSDavid Dillow len += count * sizeof (struct srp_direct_buf); 1496f5358a17SRoland Dreier 1497c07d424dSDavid Dillow memcpy(indirect_hdr->desc_list, req->indirect_desc, 1498c07d424dSDavid Dillow count * sizeof (struct srp_direct_buf)); 149985507bccSRalph Campbell 1500c07d424dSDavid Dillow indirect_hdr->table_desc.va = cpu_to_be64(req->indirect_dma_addr); 15018f26c9ffSDavid Dillow indirect_hdr->table_desc.key = cpu_to_be32(target->rkey); 15028f26c9ffSDavid Dillow indirect_hdr->table_desc.len = cpu_to_be32(table_len); 15038f26c9ffSDavid Dillow indirect_hdr->len = cpu_to_be32(state.total_len); 1504aef9ec39SRoland Dreier 1505aef9ec39SRoland Dreier if (scmnd->sc_data_direction == DMA_TO_DEVICE) 1506c07d424dSDavid Dillow cmd->data_out_desc_cnt = count; 1507aef9ec39SRoland Dreier else 1508c07d424dSDavid Dillow cmd->data_in_desc_cnt = count; 1509c07d424dSDavid Dillow 1510c07d424dSDavid Dillow ib_dma_sync_single_for_device(ibdev, req->indirect_dma_addr, table_len, 1511c07d424dSDavid Dillow DMA_TO_DEVICE); 1512aef9ec39SRoland Dreier 15138f26c9ffSDavid Dillow map_complete: 1514aef9ec39SRoland Dreier if (scmnd->sc_data_direction == DMA_TO_DEVICE) 1515aef9ec39SRoland Dreier cmd->buf_fmt = fmt << 4; 1516aef9ec39SRoland Dreier else 1517aef9ec39SRoland Dreier cmd->buf_fmt = fmt; 1518aef9ec39SRoland Dreier 1519aef9ec39SRoland Dreier return len; 1520aef9ec39SRoland Dreier } 1521aef9ec39SRoland Dreier 152205a1d750SDavid Dillow /* 152376c75b25SBart Van Assche * Return an IU and possible credit to the free pool 152476c75b25SBart Van Assche */ 152576c75b25SBart Van Assche static void srp_put_tx_iu(struct srp_target_port *target, struct srp_iu *iu, 152676c75b25SBart Van Assche enum srp_iu_type iu_type) 152776c75b25SBart Van Assche { 152876c75b25SBart Van Assche unsigned long flags; 152976c75b25SBart Van Assche 1530e9684678SBart Van Assche spin_lock_irqsave(&target->lock, flags); 153176c75b25SBart Van Assche list_add(&iu->list, &target->free_tx); 153276c75b25SBart Van Assche if (iu_type != SRP_IU_RSP) 153376c75b25SBart Van Assche ++target->req_lim; 1534e9684678SBart Van Assche spin_unlock_irqrestore(&target->lock, flags); 153576c75b25SBart Van Assche } 153676c75b25SBart Van Assche 153776c75b25SBart Van Assche /* 1538e9684678SBart Van Assche * Must be called with target->lock held to protect req_lim and free_tx. 1539e9684678SBart Van Assche * If IU is not sent, it must be returned using srp_put_tx_iu(). 154005a1d750SDavid Dillow * 154105a1d750SDavid Dillow * Note: 154205a1d750SDavid Dillow * An upper limit for the number of allocated information units for each 154305a1d750SDavid Dillow * request type is: 154405a1d750SDavid Dillow * - SRP_IU_CMD: SRP_CMD_SQ_SIZE, since the SCSI mid-layer never queues 154505a1d750SDavid Dillow * more than Scsi_Host.can_queue requests. 154605a1d750SDavid Dillow * - SRP_IU_TSK_MGMT: SRP_TSK_MGMT_SQ_SIZE. 154705a1d750SDavid Dillow * - SRP_IU_RSP: 1, since a conforming SRP target never sends more than 154805a1d750SDavid Dillow * one unanswered SRP request to an initiator. 154905a1d750SDavid Dillow */ 155005a1d750SDavid Dillow static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target, 155105a1d750SDavid Dillow enum srp_iu_type iu_type) 155205a1d750SDavid Dillow { 155305a1d750SDavid Dillow s32 rsv = (iu_type == SRP_IU_TSK_MGMT) ? 0 : SRP_TSK_MGMT_SQ_SIZE; 155405a1d750SDavid Dillow struct srp_iu *iu; 155505a1d750SDavid Dillow 155605a1d750SDavid Dillow srp_send_completion(target->send_cq, target); 155705a1d750SDavid Dillow 1558dcb4cb85SBart Van Assche if (list_empty(&target->free_tx)) 155905a1d750SDavid Dillow return NULL; 156005a1d750SDavid Dillow 156105a1d750SDavid Dillow /* Initiator responses to target requests do not consume credits */ 156276c75b25SBart Van Assche if (iu_type != SRP_IU_RSP) { 156376c75b25SBart Van Assche if (target->req_lim <= rsv) { 156405a1d750SDavid Dillow ++target->zero_req_lim; 156505a1d750SDavid Dillow return NULL; 156605a1d750SDavid Dillow } 156705a1d750SDavid Dillow 156876c75b25SBart Van Assche --target->req_lim; 156976c75b25SBart Van Assche } 157076c75b25SBart Van Assche 1571dcb4cb85SBart Van Assche iu = list_first_entry(&target->free_tx, struct srp_iu, list); 157276c75b25SBart Van Assche list_del(&iu->list); 157305a1d750SDavid Dillow return iu; 157405a1d750SDavid Dillow } 157505a1d750SDavid Dillow 157676c75b25SBart Van Assche static int srp_post_send(struct srp_target_port *target, 157705a1d750SDavid Dillow struct srp_iu *iu, int len) 157805a1d750SDavid Dillow { 157905a1d750SDavid Dillow struct ib_sge list; 158005a1d750SDavid Dillow struct ib_send_wr wr, *bad_wr; 158105a1d750SDavid Dillow 158205a1d750SDavid Dillow list.addr = iu->dma; 158305a1d750SDavid Dillow list.length = len; 15849af76271SDavid Dillow list.lkey = target->lkey; 158505a1d750SDavid Dillow 158605a1d750SDavid Dillow wr.next = NULL; 1587dcb4cb85SBart Van Assche wr.wr_id = (uintptr_t) iu; 158805a1d750SDavid Dillow wr.sg_list = &list; 158905a1d750SDavid Dillow wr.num_sge = 1; 159005a1d750SDavid Dillow wr.opcode = IB_WR_SEND; 159105a1d750SDavid Dillow wr.send_flags = IB_SEND_SIGNALED; 159205a1d750SDavid Dillow 159376c75b25SBart Van Assche return ib_post_send(target->qp, &wr, &bad_wr); 159405a1d750SDavid Dillow } 159505a1d750SDavid Dillow 1596dcb4cb85SBart Van Assche static int srp_post_recv(struct srp_target_port *target, struct srp_iu *iu) 1597c996bb47SBart Van Assche { 1598c996bb47SBart Van Assche struct ib_recv_wr wr, *bad_wr; 1599dcb4cb85SBart Van Assche struct ib_sge list; 1600c996bb47SBart Van Assche 1601c996bb47SBart Van Assche list.addr = iu->dma; 1602c996bb47SBart Van Assche list.length = iu->size; 16039af76271SDavid Dillow list.lkey = target->lkey; 1604c996bb47SBart Van Assche 1605c996bb47SBart Van Assche wr.next = NULL; 1606dcb4cb85SBart Van Assche wr.wr_id = (uintptr_t) iu; 1607c996bb47SBart Van Assche wr.sg_list = &list; 1608c996bb47SBart Van Assche wr.num_sge = 1; 1609c996bb47SBart Van Assche 1610dcb4cb85SBart Van Assche return ib_post_recv(target->qp, &wr, &bad_wr); 1611c996bb47SBart Van Assche } 1612c996bb47SBart Van Assche 1613aef9ec39SRoland Dreier static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) 1614aef9ec39SRoland Dreier { 1615aef9ec39SRoland Dreier struct srp_request *req; 1616aef9ec39SRoland Dreier struct scsi_cmnd *scmnd; 1617aef9ec39SRoland Dreier unsigned long flags; 1618aef9ec39SRoland Dreier 1619aef9ec39SRoland Dreier if (unlikely(rsp->tag & SRP_TAG_TSK_MGMT)) { 1620e9684678SBart Van Assche spin_lock_irqsave(&target->lock, flags); 162194a9174cSBart Van Assche target->req_lim += be32_to_cpu(rsp->req_lim_delta); 1622e9684678SBart Van Assche spin_unlock_irqrestore(&target->lock, flags); 162394a9174cSBart Van Assche 1624f8b6e31eSDavid Dillow target->tsk_mgmt_status = -1; 1625f8b6e31eSDavid Dillow if (be32_to_cpu(rsp->resp_data_len) >= 4) 1626f8b6e31eSDavid Dillow target->tsk_mgmt_status = rsp->data[3]; 1627f8b6e31eSDavid Dillow complete(&target->tsk_mgmt_done); 1628aef9ec39SRoland Dreier } else { 1629f8b6e31eSDavid Dillow req = &target->req_ring[rsp->tag]; 1630b3fe628dSBart Van Assche scmnd = srp_claim_req(target, req, NULL, NULL); 163122032991SBart Van Assche if (!scmnd) { 16327aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 16337aa54bd7SDavid Dillow "Null scmnd for RSP w/tag %016llx\n", 1634aef9ec39SRoland Dreier (unsigned long long) rsp->tag); 163522032991SBart Van Assche 163622032991SBart Van Assche spin_lock_irqsave(&target->lock, flags); 163722032991SBart Van Assche target->req_lim += be32_to_cpu(rsp->req_lim_delta); 163822032991SBart Van Assche spin_unlock_irqrestore(&target->lock, flags); 163922032991SBart Van Assche 164022032991SBart Van Assche return; 164122032991SBart Van Assche } 1642aef9ec39SRoland Dreier scmnd->result = rsp->status; 1643aef9ec39SRoland Dreier 1644aef9ec39SRoland Dreier if (rsp->flags & SRP_RSP_FLAG_SNSVALID) { 1645aef9ec39SRoland Dreier memcpy(scmnd->sense_buffer, rsp->data + 1646aef9ec39SRoland Dreier be32_to_cpu(rsp->resp_data_len), 1647aef9ec39SRoland Dreier min_t(int, be32_to_cpu(rsp->sense_data_len), 1648aef9ec39SRoland Dreier SCSI_SENSE_BUFFERSIZE)); 1649aef9ec39SRoland Dreier } 1650aef9ec39SRoland Dreier 1651e714531aSBart Van Assche if (unlikely(rsp->flags & SRP_RSP_FLAG_DIUNDER)) 1652bb350d1dSFUJITA Tomonori scsi_set_resid(scmnd, be32_to_cpu(rsp->data_in_res_cnt)); 1653e714531aSBart Van Assche else if (unlikely(rsp->flags & SRP_RSP_FLAG_DIOVER)) 1654e714531aSBart Van Assche scsi_set_resid(scmnd, -be32_to_cpu(rsp->data_in_res_cnt)); 1655e714531aSBart Van Assche else if (unlikely(rsp->flags & SRP_RSP_FLAG_DOUNDER)) 1656e714531aSBart Van Assche scsi_set_resid(scmnd, be32_to_cpu(rsp->data_out_res_cnt)); 1657e714531aSBart Van Assche else if (unlikely(rsp->flags & SRP_RSP_FLAG_DOOVER)) 1658e714531aSBart Van Assche scsi_set_resid(scmnd, -be32_to_cpu(rsp->data_out_res_cnt)); 1659aef9ec39SRoland Dreier 166022032991SBart Van Assche srp_free_req(target, req, scmnd, 166122032991SBart Van Assche be32_to_cpu(rsp->req_lim_delta)); 166222032991SBart Van Assche 1663f8b6e31eSDavid Dillow scmnd->host_scribble = NULL; 1664aef9ec39SRoland Dreier scmnd->scsi_done(scmnd); 1665aef9ec39SRoland Dreier } 1666aef9ec39SRoland Dreier } 1667aef9ec39SRoland Dreier 1668bb12588aSDavid Dillow static int srp_response_common(struct srp_target_port *target, s32 req_delta, 1669bb12588aSDavid Dillow void *rsp, int len) 1670bb12588aSDavid Dillow { 167176c75b25SBart Van Assche struct ib_device *dev = target->srp_host->srp_dev->dev; 1672bb12588aSDavid Dillow unsigned long flags; 1673bb12588aSDavid Dillow struct srp_iu *iu; 167476c75b25SBart Van Assche int err; 1675bb12588aSDavid Dillow 1676e9684678SBart Van Assche spin_lock_irqsave(&target->lock, flags); 1677bb12588aSDavid Dillow target->req_lim += req_delta; 1678bb12588aSDavid Dillow iu = __srp_get_tx_iu(target, SRP_IU_RSP); 1679e9684678SBart Van Assche spin_unlock_irqrestore(&target->lock, flags); 168076c75b25SBart Van Assche 1681bb12588aSDavid Dillow if (!iu) { 1682bb12588aSDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX 1683bb12588aSDavid Dillow "no IU available to send response\n"); 168476c75b25SBart Van Assche return 1; 1685bb12588aSDavid Dillow } 1686bb12588aSDavid Dillow 1687bb12588aSDavid Dillow ib_dma_sync_single_for_cpu(dev, iu->dma, len, DMA_TO_DEVICE); 1688bb12588aSDavid Dillow memcpy(iu->buf, rsp, len); 1689bb12588aSDavid Dillow ib_dma_sync_single_for_device(dev, iu->dma, len, DMA_TO_DEVICE); 1690bb12588aSDavid Dillow 169176c75b25SBart Van Assche err = srp_post_send(target, iu, len); 169276c75b25SBart Van Assche if (err) { 1693bb12588aSDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX 1694bb12588aSDavid Dillow "unable to post response: %d\n", err); 169576c75b25SBart Van Assche srp_put_tx_iu(target, iu, SRP_IU_RSP); 169676c75b25SBart Van Assche } 1697bb12588aSDavid Dillow 1698bb12588aSDavid Dillow return err; 1699bb12588aSDavid Dillow } 1700bb12588aSDavid Dillow 1701bb12588aSDavid Dillow static void srp_process_cred_req(struct srp_target_port *target, 1702bb12588aSDavid Dillow struct srp_cred_req *req) 1703bb12588aSDavid Dillow { 1704bb12588aSDavid Dillow struct srp_cred_rsp rsp = { 1705bb12588aSDavid Dillow .opcode = SRP_CRED_RSP, 1706bb12588aSDavid Dillow .tag = req->tag, 1707bb12588aSDavid Dillow }; 1708bb12588aSDavid Dillow s32 delta = be32_to_cpu(req->req_lim_delta); 1709bb12588aSDavid Dillow 1710bb12588aSDavid Dillow if (srp_response_common(target, delta, &rsp, sizeof rsp)) 1711bb12588aSDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX 1712bb12588aSDavid Dillow "problems processing SRP_CRED_REQ\n"); 1713bb12588aSDavid Dillow } 1714bb12588aSDavid Dillow 1715bb12588aSDavid Dillow static void srp_process_aer_req(struct srp_target_port *target, 1716bb12588aSDavid Dillow struct srp_aer_req *req) 1717bb12588aSDavid Dillow { 1718bb12588aSDavid Dillow struct srp_aer_rsp rsp = { 1719bb12588aSDavid Dillow .opcode = SRP_AER_RSP, 1720bb12588aSDavid Dillow .tag = req->tag, 1721bb12588aSDavid Dillow }; 1722bb12588aSDavid Dillow s32 delta = be32_to_cpu(req->req_lim_delta); 1723bb12588aSDavid Dillow 1724bb12588aSDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX 1725bb12588aSDavid Dillow "ignoring AER for LUN %llu\n", be64_to_cpu(req->lun)); 1726bb12588aSDavid Dillow 1727bb12588aSDavid Dillow if (srp_response_common(target, delta, &rsp, sizeof rsp)) 1728bb12588aSDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX 1729bb12588aSDavid Dillow "problems processing SRP_AER_REQ\n"); 1730bb12588aSDavid Dillow } 1731bb12588aSDavid Dillow 1732aef9ec39SRoland Dreier static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc) 1733aef9ec39SRoland Dreier { 1734dcb4cb85SBart Van Assche struct ib_device *dev = target->srp_host->srp_dev->dev; 1735737b94ebSRoland Dreier struct srp_iu *iu = (struct srp_iu *) (uintptr_t) wc->wr_id; 1736c996bb47SBart Van Assche int res; 1737aef9ec39SRoland Dreier u8 opcode; 1738aef9ec39SRoland Dreier 173985507bccSRalph Campbell ib_dma_sync_single_for_cpu(dev, iu->dma, target->max_ti_iu_len, 174085507bccSRalph Campbell DMA_FROM_DEVICE); 1741aef9ec39SRoland Dreier 1742aef9ec39SRoland Dreier opcode = *(u8 *) iu->buf; 1743aef9ec39SRoland Dreier 1744aef9ec39SRoland Dreier if (0) { 17457aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 17467aa54bd7SDavid Dillow PFX "recv completion, opcode 0x%02x\n", opcode); 17477a700811SBart Van Assche print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 8, 1, 17487a700811SBart Van Assche iu->buf, wc->byte_len, true); 1749aef9ec39SRoland Dreier } 1750aef9ec39SRoland Dreier 1751aef9ec39SRoland Dreier switch (opcode) { 1752aef9ec39SRoland Dreier case SRP_RSP: 1753aef9ec39SRoland Dreier srp_process_rsp(target, iu->buf); 1754aef9ec39SRoland Dreier break; 1755aef9ec39SRoland Dreier 1756bb12588aSDavid Dillow case SRP_CRED_REQ: 1757bb12588aSDavid Dillow srp_process_cred_req(target, iu->buf); 1758bb12588aSDavid Dillow break; 1759bb12588aSDavid Dillow 1760bb12588aSDavid Dillow case SRP_AER_REQ: 1761bb12588aSDavid Dillow srp_process_aer_req(target, iu->buf); 1762bb12588aSDavid Dillow break; 1763bb12588aSDavid Dillow 1764aef9ec39SRoland Dreier case SRP_T_LOGOUT: 1765aef9ec39SRoland Dreier /* XXX Handle target logout */ 17667aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 17677aa54bd7SDavid Dillow PFX "Got target logout request\n"); 1768aef9ec39SRoland Dreier break; 1769aef9ec39SRoland Dreier 1770aef9ec39SRoland Dreier default: 17717aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 17727aa54bd7SDavid Dillow PFX "Unhandled SRP opcode 0x%02x\n", opcode); 1773aef9ec39SRoland Dreier break; 1774aef9ec39SRoland Dreier } 1775aef9ec39SRoland Dreier 177685507bccSRalph Campbell ib_dma_sync_single_for_device(dev, iu->dma, target->max_ti_iu_len, 177785507bccSRalph Campbell DMA_FROM_DEVICE); 1778c996bb47SBart Van Assche 1779dcb4cb85SBart Van Assche res = srp_post_recv(target, iu); 1780c996bb47SBart Van Assche if (res != 0) 1781c996bb47SBart Van Assche shost_printk(KERN_ERR, target->scsi_host, 1782c996bb47SBart Van Assche PFX "Recv failed with error code %d\n", res); 1783aef9ec39SRoland Dreier } 1784aef9ec39SRoland Dreier 1785c1120f89SBart Van Assche /** 1786c1120f89SBart Van Assche * srp_tl_err_work() - handle a transport layer error 1787af24663bSBart Van Assche * @work: Work structure embedded in an SRP target port. 1788c1120f89SBart Van Assche * 1789c1120f89SBart Van Assche * Note: This function may get invoked before the rport has been created, 1790c1120f89SBart Van Assche * hence the target->rport test. 1791c1120f89SBart Van Assche */ 1792c1120f89SBart Van Assche static void srp_tl_err_work(struct work_struct *work) 1793c1120f89SBart Van Assche { 1794c1120f89SBart Van Assche struct srp_target_port *target; 1795c1120f89SBart Van Assche 1796c1120f89SBart Van Assche target = container_of(work, struct srp_target_port, tl_err_work); 1797c1120f89SBart Van Assche if (target->rport) 1798c1120f89SBart Van Assche srp_start_tl_fail_timers(target->rport); 1799c1120f89SBart Van Assche } 1800c1120f89SBart Van Assche 18015cfb1782SBart Van Assche static void srp_handle_qp_err(u64 wr_id, enum ib_wc_status wc_status, 18025cfb1782SBart Van Assche bool send_err, struct srp_target_port *target) 1803948d1e88SBart Van Assche { 1804294c875aSBart Van Assche if (target->connected && !target->qp_in_error) { 18055cfb1782SBart Van Assche if (wr_id & LOCAL_INV_WR_ID_MASK) { 18065cfb1782SBart Van Assche shost_printk(KERN_ERR, target->scsi_host, PFX 18075cfb1782SBart Van Assche "LOCAL_INV failed with status %d\n", 18084f0af697SBart Van Assche wc_status); 18095cfb1782SBart Van Assche } else if (wr_id & FAST_REG_WR_ID_MASK) { 18105cfb1782SBart Van Assche shost_printk(KERN_ERR, target->scsi_host, PFX 18115cfb1782SBart Van Assche "FAST_REG_MR failed status %d\n", 18125cfb1782SBart Van Assche wc_status); 18135cfb1782SBart Van Assche } else { 18145cfb1782SBart Van Assche shost_printk(KERN_ERR, target->scsi_host, 18155cfb1782SBart Van Assche PFX "failed %s status %d for iu %p\n", 18165cfb1782SBart Van Assche send_err ? "send" : "receive", 18175cfb1782SBart Van Assche wc_status, (void *)(uintptr_t)wr_id); 18185cfb1782SBart Van Assche } 1819c1120f89SBart Van Assche queue_work(system_long_wq, &target->tl_err_work); 18204f0af697SBart Van Assche } 1821948d1e88SBart Van Assche target->qp_in_error = true; 1822948d1e88SBart Van Assche } 1823948d1e88SBart Van Assche 18249c03dc9fSBart Van Assche static void srp_recv_completion(struct ib_cq *cq, void *target_ptr) 1825aef9ec39SRoland Dreier { 1826aef9ec39SRoland Dreier struct srp_target_port *target = target_ptr; 1827aef9ec39SRoland Dreier struct ib_wc wc; 1828aef9ec39SRoland Dreier 1829aef9ec39SRoland Dreier ib_req_notify_cq(cq, IB_CQ_NEXT_COMP); 1830aef9ec39SRoland Dreier while (ib_poll_cq(cq, 1, &wc) > 0) { 1831948d1e88SBart Van Assche if (likely(wc.status == IB_WC_SUCCESS)) { 1832948d1e88SBart Van Assche srp_handle_recv(target, &wc); 1833948d1e88SBart Van Assche } else { 18345cfb1782SBart Van Assche srp_handle_qp_err(wc.wr_id, wc.status, false, target); 1835aef9ec39SRoland Dreier } 18369c03dc9fSBart Van Assche } 18379c03dc9fSBart Van Assche } 18389c03dc9fSBart Van Assche 18399c03dc9fSBart Van Assche static void srp_send_completion(struct ib_cq *cq, void *target_ptr) 18409c03dc9fSBart Van Assche { 18419c03dc9fSBart Van Assche struct srp_target_port *target = target_ptr; 18429c03dc9fSBart Van Assche struct ib_wc wc; 1843dcb4cb85SBart Van Assche struct srp_iu *iu; 18449c03dc9fSBart Van Assche 18459c03dc9fSBart Van Assche while (ib_poll_cq(cq, 1, &wc) > 0) { 1846948d1e88SBart Van Assche if (likely(wc.status == IB_WC_SUCCESS)) { 1847737b94ebSRoland Dreier iu = (struct srp_iu *) (uintptr_t) wc.wr_id; 1848dcb4cb85SBart Van Assche list_add(&iu->list, &target->free_tx); 1849948d1e88SBart Van Assche } else { 18505cfb1782SBart Van Assche srp_handle_qp_err(wc.wr_id, wc.status, true, target); 1851948d1e88SBart Van Assche } 1852aef9ec39SRoland Dreier } 1853aef9ec39SRoland Dreier } 1854aef9ec39SRoland Dreier 185576c75b25SBart Van Assche static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd) 1856aef9ec39SRoland Dreier { 185776c75b25SBart Van Assche struct srp_target_port *target = host_to_target(shost); 1858a95cadb9SBart Van Assche struct srp_rport *rport = target->rport; 1859aef9ec39SRoland Dreier struct srp_request *req; 1860aef9ec39SRoland Dreier struct srp_iu *iu; 1861aef9ec39SRoland Dreier struct srp_cmd *cmd; 186285507bccSRalph Campbell struct ib_device *dev; 186376c75b25SBart Van Assche unsigned long flags; 1864d1b4289eSBart Van Assche int len, ret; 1865a95cadb9SBart Van Assche const bool in_scsi_eh = !in_interrupt() && current == shost->ehandler; 1866a95cadb9SBart Van Assche 1867a95cadb9SBart Van Assche /* 1868a95cadb9SBart Van Assche * The SCSI EH thread is the only context from which srp_queuecommand() 1869a95cadb9SBart Van Assche * can get invoked for blocked devices (SDEV_BLOCK / 1870a95cadb9SBart Van Assche * SDEV_CREATED_BLOCK). Avoid racing with srp_reconnect_rport() by 1871a95cadb9SBart Van Assche * locking the rport mutex if invoked from inside the SCSI EH. 1872a95cadb9SBart Van Assche */ 1873a95cadb9SBart Van Assche if (in_scsi_eh) 1874a95cadb9SBart Van Assche mutex_lock(&rport->mutex); 1875aef9ec39SRoland Dreier 1876d1b4289eSBart Van Assche scmnd->result = srp_chkready(target->rport); 1877d1b4289eSBart Van Assche if (unlikely(scmnd->result)) 1878d1b4289eSBart Van Assche goto err; 18792ce19e72SBart Van Assche 1880e9684678SBart Van Assche spin_lock_irqsave(&target->lock, flags); 1881bb12588aSDavid Dillow iu = __srp_get_tx_iu(target, SRP_IU_CMD); 1882aef9ec39SRoland Dreier if (!iu) 1883695b8349SBart Van Assche goto err_unlock; 1884695b8349SBart Van Assche 1885695b8349SBart Van Assche req = list_first_entry(&target->free_reqs, struct srp_request, list); 1886695b8349SBart Van Assche list_del(&req->list); 1887695b8349SBart Van Assche spin_unlock_irqrestore(&target->lock, flags); 1888aef9ec39SRoland Dreier 188905321937SGreg Kroah-Hartman dev = target->srp_host->srp_dev->dev; 189049248644SDavid Dillow ib_dma_sync_single_for_cpu(dev, iu->dma, target->max_iu_len, 189185507bccSRalph Campbell DMA_TO_DEVICE); 1892aef9ec39SRoland Dreier 1893f8b6e31eSDavid Dillow scmnd->host_scribble = (void *) req; 1894aef9ec39SRoland Dreier 1895aef9ec39SRoland Dreier cmd = iu->buf; 1896aef9ec39SRoland Dreier memset(cmd, 0, sizeof *cmd); 1897aef9ec39SRoland Dreier 1898aef9ec39SRoland Dreier cmd->opcode = SRP_CMD; 1899aef9ec39SRoland Dreier cmd->lun = cpu_to_be64((u64) scmnd->device->lun << 48); 1900d945e1dfSRoland Dreier cmd->tag = req->index; 1901aef9ec39SRoland Dreier memcpy(cmd->cdb, scmnd->cmnd, scmnd->cmd_len); 1902aef9ec39SRoland Dreier 1903aef9ec39SRoland Dreier req->scmnd = scmnd; 1904aef9ec39SRoland Dreier req->cmd = iu; 1905aef9ec39SRoland Dreier 1906aef9ec39SRoland Dreier len = srp_map_data(scmnd, target, req); 1907aef9ec39SRoland Dreier if (len < 0) { 19087aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 1909d1b4289eSBart Van Assche PFX "Failed to map data (%d)\n", len); 1910d1b4289eSBart Van Assche /* 1911d1b4289eSBart Van Assche * If we ran out of memory descriptors (-ENOMEM) because an 1912d1b4289eSBart Van Assche * application is queuing many requests with more than 191352ede08fSBart Van Assche * max_pages_per_mr sg-list elements, tell the SCSI mid-layer 1914d1b4289eSBart Van Assche * to reduce queue depth temporarily. 1915d1b4289eSBart Van Assche */ 1916d1b4289eSBart Van Assche scmnd->result = len == -ENOMEM ? 1917d1b4289eSBart Van Assche DID_OK << 16 | QUEUE_FULL << 1 : DID_ERROR << 16; 191876c75b25SBart Van Assche goto err_iu; 1919aef9ec39SRoland Dreier } 1920aef9ec39SRoland Dreier 192149248644SDavid Dillow ib_dma_sync_single_for_device(dev, iu->dma, target->max_iu_len, 192285507bccSRalph Campbell DMA_TO_DEVICE); 1923aef9ec39SRoland Dreier 192476c75b25SBart Van Assche if (srp_post_send(target, iu, len)) { 19257aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX "Send failed\n"); 1926aef9ec39SRoland Dreier goto err_unmap; 1927aef9ec39SRoland Dreier } 1928aef9ec39SRoland Dreier 1929d1b4289eSBart Van Assche ret = 0; 1930d1b4289eSBart Van Assche 1931a95cadb9SBart Van Assche unlock_rport: 1932a95cadb9SBart Van Assche if (in_scsi_eh) 1933a95cadb9SBart Van Assche mutex_unlock(&rport->mutex); 1934a95cadb9SBart Van Assche 1935d1b4289eSBart Van Assche return ret; 1936aef9ec39SRoland Dreier 1937aef9ec39SRoland Dreier err_unmap: 1938aef9ec39SRoland Dreier srp_unmap_data(scmnd, target, req); 1939aef9ec39SRoland Dreier 194076c75b25SBart Van Assche err_iu: 194176c75b25SBart Van Assche srp_put_tx_iu(target, iu, SRP_IU_CMD); 194276c75b25SBart Van Assche 1943024ca901SBart Van Assche /* 1944024ca901SBart Van Assche * Avoid that the loops that iterate over the request ring can 1945024ca901SBart Van Assche * encounter a dangling SCSI command pointer. 1946024ca901SBart Van Assche */ 1947024ca901SBart Van Assche req->scmnd = NULL; 1948024ca901SBart Van Assche 1949e9684678SBart Van Assche spin_lock_irqsave(&target->lock, flags); 195076c75b25SBart Van Assche list_add(&req->list, &target->free_reqs); 1951695b8349SBart Van Assche 1952695b8349SBart Van Assche err_unlock: 1953e9684678SBart Van Assche spin_unlock_irqrestore(&target->lock, flags); 195476c75b25SBart Van Assche 1955d1b4289eSBart Van Assche err: 1956d1b4289eSBart Van Assche if (scmnd->result) { 1957d1b4289eSBart Van Assche scmnd->scsi_done(scmnd); 1958d1b4289eSBart Van Assche ret = 0; 1959d1b4289eSBart Van Assche } else { 1960d1b4289eSBart Van Assche ret = SCSI_MLQUEUE_HOST_BUSY; 1961d1b4289eSBart Van Assche } 1962a95cadb9SBart Van Assche 1963d1b4289eSBart Van Assche goto unlock_rport; 1964aef9ec39SRoland Dreier } 1965aef9ec39SRoland Dreier 19664d73f95fSBart Van Assche /* 19674d73f95fSBart Van Assche * Note: the resources allocated in this function are freed in 19684d73f95fSBart Van Assche * srp_free_target_ib(). 19694d73f95fSBart Van Assche */ 1970aef9ec39SRoland Dreier static int srp_alloc_iu_bufs(struct srp_target_port *target) 1971aef9ec39SRoland Dreier { 1972aef9ec39SRoland Dreier int i; 1973aef9ec39SRoland Dreier 19744d73f95fSBart Van Assche target->rx_ring = kzalloc(target->queue_size * sizeof(*target->rx_ring), 19754d73f95fSBart Van Assche GFP_KERNEL); 19764d73f95fSBart Van Assche if (!target->rx_ring) 19774d73f95fSBart Van Assche goto err_no_ring; 19784d73f95fSBart Van Assche target->tx_ring = kzalloc(target->queue_size * sizeof(*target->tx_ring), 19794d73f95fSBart Van Assche GFP_KERNEL); 19804d73f95fSBart Van Assche if (!target->tx_ring) 19814d73f95fSBart Van Assche goto err_no_ring; 19824d73f95fSBart Van Assche 19834d73f95fSBart Van Assche for (i = 0; i < target->queue_size; ++i) { 1984aef9ec39SRoland Dreier target->rx_ring[i] = srp_alloc_iu(target->srp_host, 1985aef9ec39SRoland Dreier target->max_ti_iu_len, 1986aef9ec39SRoland Dreier GFP_KERNEL, DMA_FROM_DEVICE); 1987aef9ec39SRoland Dreier if (!target->rx_ring[i]) 1988aef9ec39SRoland Dreier goto err; 1989aef9ec39SRoland Dreier } 1990aef9ec39SRoland Dreier 19914d73f95fSBart Van Assche for (i = 0; i < target->queue_size; ++i) { 1992aef9ec39SRoland Dreier target->tx_ring[i] = srp_alloc_iu(target->srp_host, 199349248644SDavid Dillow target->max_iu_len, 1994aef9ec39SRoland Dreier GFP_KERNEL, DMA_TO_DEVICE); 1995aef9ec39SRoland Dreier if (!target->tx_ring[i]) 1996aef9ec39SRoland Dreier goto err; 1997dcb4cb85SBart Van Assche 1998dcb4cb85SBart Van Assche list_add(&target->tx_ring[i]->list, &target->free_tx); 1999aef9ec39SRoland Dreier } 2000aef9ec39SRoland Dreier 2001aef9ec39SRoland Dreier return 0; 2002aef9ec39SRoland Dreier 2003aef9ec39SRoland Dreier err: 20044d73f95fSBart Van Assche for (i = 0; i < target->queue_size; ++i) { 2005aef9ec39SRoland Dreier srp_free_iu(target->srp_host, target->rx_ring[i]); 20064d73f95fSBart Van Assche srp_free_iu(target->srp_host, target->tx_ring[i]); 2007aef9ec39SRoland Dreier } 2008aef9ec39SRoland Dreier 20094d73f95fSBart Van Assche 20104d73f95fSBart Van Assche err_no_ring: 20114d73f95fSBart Van Assche kfree(target->tx_ring); 20124d73f95fSBart Van Assche target->tx_ring = NULL; 20134d73f95fSBart Van Assche kfree(target->rx_ring); 20144d73f95fSBart Van Assche target->rx_ring = NULL; 2015aef9ec39SRoland Dreier 2016aef9ec39SRoland Dreier return -ENOMEM; 2017aef9ec39SRoland Dreier } 2018aef9ec39SRoland Dreier 2019c9b03c1aSBart Van Assche static uint32_t srp_compute_rq_tmo(struct ib_qp_attr *qp_attr, int attr_mask) 2020c9b03c1aSBart Van Assche { 2021c9b03c1aSBart Van Assche uint64_t T_tr_ns, max_compl_time_ms; 2022c9b03c1aSBart Van Assche uint32_t rq_tmo_jiffies; 2023c9b03c1aSBart Van Assche 2024c9b03c1aSBart Van Assche /* 2025c9b03c1aSBart Van Assche * According to section 11.2.4.2 in the IBTA spec (Modify Queue Pair, 2026c9b03c1aSBart Van Assche * table 91), both the QP timeout and the retry count have to be set 2027c9b03c1aSBart Van Assche * for RC QP's during the RTR to RTS transition. 2028c9b03c1aSBart Van Assche */ 2029c9b03c1aSBart Van Assche WARN_ON_ONCE((attr_mask & (IB_QP_TIMEOUT | IB_QP_RETRY_CNT)) != 2030c9b03c1aSBart Van Assche (IB_QP_TIMEOUT | IB_QP_RETRY_CNT)); 2031c9b03c1aSBart Van Assche 2032c9b03c1aSBart Van Assche /* 2033c9b03c1aSBart Van Assche * Set target->rq_tmo_jiffies to one second more than the largest time 2034c9b03c1aSBart Van Assche * it can take before an error completion is generated. See also 2035c9b03c1aSBart Van Assche * C9-140..142 in the IBTA spec for more information about how to 2036c9b03c1aSBart Van Assche * convert the QP Local ACK Timeout value to nanoseconds. 2037c9b03c1aSBart Van Assche */ 2038c9b03c1aSBart Van Assche T_tr_ns = 4096 * (1ULL << qp_attr->timeout); 2039c9b03c1aSBart Van Assche max_compl_time_ms = qp_attr->retry_cnt * 4 * T_tr_ns; 2040c9b03c1aSBart Van Assche do_div(max_compl_time_ms, NSEC_PER_MSEC); 2041c9b03c1aSBart Van Assche rq_tmo_jiffies = msecs_to_jiffies(max_compl_time_ms + 1000); 2042c9b03c1aSBart Van Assche 2043c9b03c1aSBart Van Assche return rq_tmo_jiffies; 2044c9b03c1aSBart Van Assche } 2045c9b03c1aSBart Van Assche 2046961e0be8SDavid Dillow static void srp_cm_rep_handler(struct ib_cm_id *cm_id, 2047961e0be8SDavid Dillow struct srp_login_rsp *lrsp, 2048961e0be8SDavid Dillow struct srp_target_port *target) 2049961e0be8SDavid Dillow { 2050961e0be8SDavid Dillow struct ib_qp_attr *qp_attr = NULL; 2051961e0be8SDavid Dillow int attr_mask = 0; 2052961e0be8SDavid Dillow int ret; 2053961e0be8SDavid Dillow int i; 2054961e0be8SDavid Dillow 2055961e0be8SDavid Dillow if (lrsp->opcode == SRP_LOGIN_RSP) { 2056961e0be8SDavid Dillow target->max_ti_iu_len = be32_to_cpu(lrsp->max_ti_iu_len); 2057961e0be8SDavid Dillow target->req_lim = be32_to_cpu(lrsp->req_lim_delta); 2058961e0be8SDavid Dillow 2059961e0be8SDavid Dillow /* 2060961e0be8SDavid Dillow * Reserve credits for task management so we don't 2061961e0be8SDavid Dillow * bounce requests back to the SCSI mid-layer. 2062961e0be8SDavid Dillow */ 2063961e0be8SDavid Dillow target->scsi_host->can_queue 2064961e0be8SDavid Dillow = min(target->req_lim - SRP_TSK_MGMT_SQ_SIZE, 2065961e0be8SDavid Dillow target->scsi_host->can_queue); 20664d73f95fSBart Van Assche target->scsi_host->cmd_per_lun 20674d73f95fSBart Van Assche = min_t(int, target->scsi_host->can_queue, 20684d73f95fSBart Van Assche target->scsi_host->cmd_per_lun); 2069961e0be8SDavid Dillow } else { 2070961e0be8SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 2071961e0be8SDavid Dillow PFX "Unhandled RSP opcode %#x\n", lrsp->opcode); 2072961e0be8SDavid Dillow ret = -ECONNRESET; 2073961e0be8SDavid Dillow goto error; 2074961e0be8SDavid Dillow } 2075961e0be8SDavid Dillow 20764d73f95fSBart Van Assche if (!target->rx_ring) { 2077961e0be8SDavid Dillow ret = srp_alloc_iu_bufs(target); 2078961e0be8SDavid Dillow if (ret) 2079961e0be8SDavid Dillow goto error; 2080961e0be8SDavid Dillow } 2081961e0be8SDavid Dillow 2082961e0be8SDavid Dillow ret = -ENOMEM; 2083961e0be8SDavid Dillow qp_attr = kmalloc(sizeof *qp_attr, GFP_KERNEL); 2084961e0be8SDavid Dillow if (!qp_attr) 2085961e0be8SDavid Dillow goto error; 2086961e0be8SDavid Dillow 2087961e0be8SDavid Dillow qp_attr->qp_state = IB_QPS_RTR; 2088961e0be8SDavid Dillow ret = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask); 2089961e0be8SDavid Dillow if (ret) 2090961e0be8SDavid Dillow goto error_free; 2091961e0be8SDavid Dillow 2092961e0be8SDavid Dillow ret = ib_modify_qp(target->qp, qp_attr, attr_mask); 2093961e0be8SDavid Dillow if (ret) 2094961e0be8SDavid Dillow goto error_free; 2095961e0be8SDavid Dillow 20964d73f95fSBart Van Assche for (i = 0; i < target->queue_size; i++) { 2097961e0be8SDavid Dillow struct srp_iu *iu = target->rx_ring[i]; 2098961e0be8SDavid Dillow ret = srp_post_recv(target, iu); 2099961e0be8SDavid Dillow if (ret) 2100961e0be8SDavid Dillow goto error_free; 2101961e0be8SDavid Dillow } 2102961e0be8SDavid Dillow 2103961e0be8SDavid Dillow qp_attr->qp_state = IB_QPS_RTS; 2104961e0be8SDavid Dillow ret = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask); 2105961e0be8SDavid Dillow if (ret) 2106961e0be8SDavid Dillow goto error_free; 2107961e0be8SDavid Dillow 2108c9b03c1aSBart Van Assche target->rq_tmo_jiffies = srp_compute_rq_tmo(qp_attr, attr_mask); 2109c9b03c1aSBart Van Assche 2110961e0be8SDavid Dillow ret = ib_modify_qp(target->qp, qp_attr, attr_mask); 2111961e0be8SDavid Dillow if (ret) 2112961e0be8SDavid Dillow goto error_free; 2113961e0be8SDavid Dillow 2114961e0be8SDavid Dillow ret = ib_send_cm_rtu(cm_id, NULL, 0); 2115961e0be8SDavid Dillow 2116961e0be8SDavid Dillow error_free: 2117961e0be8SDavid Dillow kfree(qp_attr); 2118961e0be8SDavid Dillow 2119961e0be8SDavid Dillow error: 2120961e0be8SDavid Dillow target->status = ret; 2121961e0be8SDavid Dillow } 2122961e0be8SDavid Dillow 2123aef9ec39SRoland Dreier static void srp_cm_rej_handler(struct ib_cm_id *cm_id, 2124aef9ec39SRoland Dreier struct ib_cm_event *event, 2125aef9ec39SRoland Dreier struct srp_target_port *target) 2126aef9ec39SRoland Dreier { 21277aa54bd7SDavid Dillow struct Scsi_Host *shost = target->scsi_host; 2128aef9ec39SRoland Dreier struct ib_class_port_info *cpi; 2129aef9ec39SRoland Dreier int opcode; 2130aef9ec39SRoland Dreier 2131aef9ec39SRoland Dreier switch (event->param.rej_rcvd.reason) { 2132aef9ec39SRoland Dreier case IB_CM_REJ_PORT_CM_REDIRECT: 2133aef9ec39SRoland Dreier cpi = event->param.rej_rcvd.ari; 2134aef9ec39SRoland Dreier target->path.dlid = cpi->redirect_lid; 2135aef9ec39SRoland Dreier target->path.pkey = cpi->redirect_pkey; 2136aef9ec39SRoland Dreier cm_id->remote_cm_qpn = be32_to_cpu(cpi->redirect_qp) & 0x00ffffff; 2137aef9ec39SRoland Dreier memcpy(target->path.dgid.raw, cpi->redirect_gid, 16); 2138aef9ec39SRoland Dreier 2139aef9ec39SRoland Dreier target->status = target->path.dlid ? 2140aef9ec39SRoland Dreier SRP_DLID_REDIRECT : SRP_PORT_REDIRECT; 2141aef9ec39SRoland Dreier break; 2142aef9ec39SRoland Dreier 2143aef9ec39SRoland Dreier case IB_CM_REJ_PORT_REDIRECT: 21445d7cbfd6SRoland Dreier if (srp_target_is_topspin(target)) { 2145aef9ec39SRoland Dreier /* 2146aef9ec39SRoland Dreier * Topspin/Cisco SRP gateways incorrectly send 2147aef9ec39SRoland Dreier * reject reason code 25 when they mean 24 2148aef9ec39SRoland Dreier * (port redirect). 2149aef9ec39SRoland Dreier */ 2150aef9ec39SRoland Dreier memcpy(target->path.dgid.raw, 2151aef9ec39SRoland Dreier event->param.rej_rcvd.ari, 16); 2152aef9ec39SRoland Dreier 21537aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, shost, 21547aa54bd7SDavid Dillow PFX "Topspin/Cisco redirect to target port GID %016llx%016llx\n", 2155aef9ec39SRoland Dreier (unsigned long long) be64_to_cpu(target->path.dgid.global.subnet_prefix), 2156aef9ec39SRoland Dreier (unsigned long long) be64_to_cpu(target->path.dgid.global.interface_id)); 2157aef9ec39SRoland Dreier 2158aef9ec39SRoland Dreier target->status = SRP_PORT_REDIRECT; 2159aef9ec39SRoland Dreier } else { 21607aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, 21617aa54bd7SDavid Dillow " REJ reason: IB_CM_REJ_PORT_REDIRECT\n"); 2162aef9ec39SRoland Dreier target->status = -ECONNRESET; 2163aef9ec39SRoland Dreier } 2164aef9ec39SRoland Dreier break; 2165aef9ec39SRoland Dreier 2166aef9ec39SRoland Dreier case IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID: 21677aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, 21687aa54bd7SDavid Dillow " REJ reason: IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID\n"); 2169aef9ec39SRoland Dreier target->status = -ECONNRESET; 2170aef9ec39SRoland Dreier break; 2171aef9ec39SRoland Dreier 2172aef9ec39SRoland Dreier case IB_CM_REJ_CONSUMER_DEFINED: 2173aef9ec39SRoland Dreier opcode = *(u8 *) event->private_data; 2174aef9ec39SRoland Dreier if (opcode == SRP_LOGIN_REJ) { 2175aef9ec39SRoland Dreier struct srp_login_rej *rej = event->private_data; 2176aef9ec39SRoland Dreier u32 reason = be32_to_cpu(rej->reason); 2177aef9ec39SRoland Dreier 2178aef9ec39SRoland Dreier if (reason == SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE) 21797aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, 21807aa54bd7SDavid Dillow PFX "SRP_LOGIN_REJ: requested max_it_iu_len too large\n"); 2181aef9ec39SRoland Dreier else 2182e7ffde01SBart Van Assche shost_printk(KERN_WARNING, shost, PFX 2183e7ffde01SBart Van Assche "SRP LOGIN from %pI6 to %pI6 REJECTED, reason 0x%08x\n", 2184e7ffde01SBart Van Assche target->path.sgid.raw, 2185e7ffde01SBart Van Assche target->orig_dgid, reason); 2186aef9ec39SRoland Dreier } else 21877aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, 21887aa54bd7SDavid Dillow " REJ reason: IB_CM_REJ_CONSUMER_DEFINED," 2189aef9ec39SRoland Dreier " opcode 0x%02x\n", opcode); 2190aef9ec39SRoland Dreier target->status = -ECONNRESET; 2191aef9ec39SRoland Dreier break; 2192aef9ec39SRoland Dreier 21939fe4bcf4SDavid Dillow case IB_CM_REJ_STALE_CONN: 21949fe4bcf4SDavid Dillow shost_printk(KERN_WARNING, shost, " REJ reason: stale connection\n"); 21959fe4bcf4SDavid Dillow target->status = SRP_STALE_CONN; 21969fe4bcf4SDavid Dillow break; 21979fe4bcf4SDavid Dillow 2198aef9ec39SRoland Dreier default: 21997aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, " REJ reason 0x%x\n", 2200aef9ec39SRoland Dreier event->param.rej_rcvd.reason); 2201aef9ec39SRoland Dreier target->status = -ECONNRESET; 2202aef9ec39SRoland Dreier } 2203aef9ec39SRoland Dreier } 2204aef9ec39SRoland Dreier 2205aef9ec39SRoland Dreier static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) 2206aef9ec39SRoland Dreier { 2207aef9ec39SRoland Dreier struct srp_target_port *target = cm_id->context; 2208aef9ec39SRoland Dreier int comp = 0; 2209aef9ec39SRoland Dreier 2210aef9ec39SRoland Dreier switch (event->event) { 2211aef9ec39SRoland Dreier case IB_CM_REQ_ERROR: 22127aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, target->scsi_host, 22137aa54bd7SDavid Dillow PFX "Sending CM REQ failed\n"); 2214aef9ec39SRoland Dreier comp = 1; 2215aef9ec39SRoland Dreier target->status = -ECONNRESET; 2216aef9ec39SRoland Dreier break; 2217aef9ec39SRoland Dreier 2218aef9ec39SRoland Dreier case IB_CM_REP_RECEIVED: 2219aef9ec39SRoland Dreier comp = 1; 2220961e0be8SDavid Dillow srp_cm_rep_handler(cm_id, event->private_data, target); 2221aef9ec39SRoland Dreier break; 2222aef9ec39SRoland Dreier 2223aef9ec39SRoland Dreier case IB_CM_REJ_RECEIVED: 22247aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, target->scsi_host, PFX "REJ received\n"); 2225aef9ec39SRoland Dreier comp = 1; 2226aef9ec39SRoland Dreier 2227aef9ec39SRoland Dreier srp_cm_rej_handler(cm_id, event, target); 2228aef9ec39SRoland Dreier break; 2229aef9ec39SRoland Dreier 2230b7ac4ab4SIshai Rabinovitz case IB_CM_DREQ_RECEIVED: 22317aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 22327aa54bd7SDavid Dillow PFX "DREQ received - connection closed\n"); 2233294c875aSBart Van Assche srp_change_conn_state(target, false); 2234b7ac4ab4SIshai Rabinovitz if (ib_send_cm_drep(cm_id, NULL, 0)) 22357aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 22367aa54bd7SDavid Dillow PFX "Sending CM DREP failed\n"); 2237c1120f89SBart Van Assche queue_work(system_long_wq, &target->tl_err_work); 2238aef9ec39SRoland Dreier break; 2239aef9ec39SRoland Dreier 2240aef9ec39SRoland Dreier case IB_CM_TIMEWAIT_EXIT: 22417aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 22427aa54bd7SDavid Dillow PFX "connection closed\n"); 2243ac72d766SBart Van Assche comp = 1; 2244aef9ec39SRoland Dreier 2245aef9ec39SRoland Dreier target->status = 0; 2246aef9ec39SRoland Dreier break; 2247aef9ec39SRoland Dreier 2248b7ac4ab4SIshai Rabinovitz case IB_CM_MRA_RECEIVED: 2249b7ac4ab4SIshai Rabinovitz case IB_CM_DREQ_ERROR: 2250b7ac4ab4SIshai Rabinovitz case IB_CM_DREP_RECEIVED: 2251b7ac4ab4SIshai Rabinovitz break; 2252b7ac4ab4SIshai Rabinovitz 2253aef9ec39SRoland Dreier default: 22547aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 22557aa54bd7SDavid Dillow PFX "Unhandled CM event %d\n", event->event); 2256aef9ec39SRoland Dreier break; 2257aef9ec39SRoland Dreier } 2258aef9ec39SRoland Dreier 2259aef9ec39SRoland Dreier if (comp) 2260aef9ec39SRoland Dreier complete(&target->done); 2261aef9ec39SRoland Dreier 2262aef9ec39SRoland Dreier return 0; 2263aef9ec39SRoland Dreier } 2264aef9ec39SRoland Dreier 226571444b97SJack Wang /** 226671444b97SJack Wang * srp_change_queue_depth - setting device queue depth 226771444b97SJack Wang * @sdev: scsi device struct 226871444b97SJack Wang * @qdepth: requested queue depth 226971444b97SJack Wang * @reason: SCSI_QDEPTH_DEFAULT/SCSI_QDEPTH_QFULL/SCSI_QDEPTH_RAMP_UP 227071444b97SJack Wang * (see include/scsi/scsi_host.h for definition) 227171444b97SJack Wang * 227271444b97SJack Wang * Returns queue depth. 227371444b97SJack Wang */ 227471444b97SJack Wang static int 227571444b97SJack Wang srp_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason) 227671444b97SJack Wang { 227771444b97SJack Wang struct Scsi_Host *shost = sdev->host; 227871444b97SJack Wang int max_depth; 227971444b97SJack Wang if (reason == SCSI_QDEPTH_DEFAULT || reason == SCSI_QDEPTH_RAMP_UP) { 228071444b97SJack Wang max_depth = shost->can_queue; 228171444b97SJack Wang if (!sdev->tagged_supported) 228271444b97SJack Wang max_depth = 1; 228371444b97SJack Wang if (qdepth > max_depth) 228471444b97SJack Wang qdepth = max_depth; 2285c8b09f6fSChristoph Hellwig scsi_adjust_queue_depth(sdev, qdepth); 228671444b97SJack Wang } else if (reason == SCSI_QDEPTH_QFULL) 228771444b97SJack Wang scsi_track_queue_full(sdev, qdepth); 228871444b97SJack Wang else 228971444b97SJack Wang return -EOPNOTSUPP; 229071444b97SJack Wang 229171444b97SJack Wang return sdev->queue_depth; 229271444b97SJack Wang } 229371444b97SJack Wang 2294d945e1dfSRoland Dreier static int srp_send_tsk_mgmt(struct srp_target_port *target, 2295f8b6e31eSDavid Dillow u64 req_tag, unsigned int lun, u8 func) 2296aef9ec39SRoland Dreier { 2297a95cadb9SBart Van Assche struct srp_rport *rport = target->rport; 229819081f31SDavid Dillow struct ib_device *dev = target->srp_host->srp_dev->dev; 2299aef9ec39SRoland Dreier struct srp_iu *iu; 2300aef9ec39SRoland Dreier struct srp_tsk_mgmt *tsk_mgmt; 2301aef9ec39SRoland Dreier 23023780d1f0SBart Van Assche if (!target->connected || target->qp_in_error) 23033780d1f0SBart Van Assche return -1; 23043780d1f0SBart Van Assche 2305f8b6e31eSDavid Dillow init_completion(&target->tsk_mgmt_done); 2306aef9ec39SRoland Dreier 2307a95cadb9SBart Van Assche /* 2308a95cadb9SBart Van Assche * Lock the rport mutex to avoid that srp_create_target_ib() is 2309a95cadb9SBart Van Assche * invoked while a task management function is being sent. 2310a95cadb9SBart Van Assche */ 2311a95cadb9SBart Van Assche mutex_lock(&rport->mutex); 2312e9684678SBart Van Assche spin_lock_irq(&target->lock); 2313bb12588aSDavid Dillow iu = __srp_get_tx_iu(target, SRP_IU_TSK_MGMT); 2314e9684678SBart Van Assche spin_unlock_irq(&target->lock); 231576c75b25SBart Van Assche 2316a95cadb9SBart Van Assche if (!iu) { 2317a95cadb9SBart Van Assche mutex_unlock(&rport->mutex); 2318a95cadb9SBart Van Assche 231976c75b25SBart Van Assche return -1; 2320a95cadb9SBart Van Assche } 2321aef9ec39SRoland Dreier 232219081f31SDavid Dillow ib_dma_sync_single_for_cpu(dev, iu->dma, sizeof *tsk_mgmt, 232319081f31SDavid Dillow DMA_TO_DEVICE); 2324aef9ec39SRoland Dreier tsk_mgmt = iu->buf; 2325aef9ec39SRoland Dreier memset(tsk_mgmt, 0, sizeof *tsk_mgmt); 2326aef9ec39SRoland Dreier 2327aef9ec39SRoland Dreier tsk_mgmt->opcode = SRP_TSK_MGMT; 2328f8b6e31eSDavid Dillow tsk_mgmt->lun = cpu_to_be64((u64) lun << 48); 2329f8b6e31eSDavid Dillow tsk_mgmt->tag = req_tag | SRP_TAG_TSK_MGMT; 2330aef9ec39SRoland Dreier tsk_mgmt->tsk_mgmt_func = func; 2331f8b6e31eSDavid Dillow tsk_mgmt->task_tag = req_tag; 2332aef9ec39SRoland Dreier 233319081f31SDavid Dillow ib_dma_sync_single_for_device(dev, iu->dma, sizeof *tsk_mgmt, 233419081f31SDavid Dillow DMA_TO_DEVICE); 233576c75b25SBart Van Assche if (srp_post_send(target, iu, sizeof *tsk_mgmt)) { 233676c75b25SBart Van Assche srp_put_tx_iu(target, iu, SRP_IU_TSK_MGMT); 2337a95cadb9SBart Van Assche mutex_unlock(&rport->mutex); 2338a95cadb9SBart Van Assche 233976c75b25SBart Van Assche return -1; 234076c75b25SBart Van Assche } 2341a95cadb9SBart Van Assche mutex_unlock(&rport->mutex); 2342d945e1dfSRoland Dreier 2343f8b6e31eSDavid Dillow if (!wait_for_completion_timeout(&target->tsk_mgmt_done, 2344aef9ec39SRoland Dreier msecs_to_jiffies(SRP_ABORT_TIMEOUT_MS))) 2345d945e1dfSRoland Dreier return -1; 2346aef9ec39SRoland Dreier 2347d945e1dfSRoland Dreier return 0; 2348d945e1dfSRoland Dreier } 2349d945e1dfSRoland Dreier 2350aef9ec39SRoland Dreier static int srp_abort(struct scsi_cmnd *scmnd) 2351aef9ec39SRoland Dreier { 2352d945e1dfSRoland Dreier struct srp_target_port *target = host_to_target(scmnd->device->host); 2353f8b6e31eSDavid Dillow struct srp_request *req = (struct srp_request *) scmnd->host_scribble; 2354086f44f5SBart Van Assche int ret; 2355d945e1dfSRoland Dreier 23567aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n"); 2357aef9ec39SRoland Dreier 2358b3fe628dSBart Van Assche if (!req || !srp_claim_req(target, req, NULL, scmnd)) 235999b6697aSBart Van Assche return SUCCESS; 2360086f44f5SBart Van Assche if (srp_send_tsk_mgmt(target, req->index, scmnd->device->lun, 236180d5e8a2SBart Van Assche SRP_TSK_ABORT_TASK) == 0) 2362086f44f5SBart Van Assche ret = SUCCESS; 2363ed9b2264SBart Van Assche else if (target->rport->state == SRP_RPORT_LOST) 236499e1c139SBart Van Assche ret = FAST_IO_FAIL; 2365086f44f5SBart Van Assche else 2366086f44f5SBart Van Assche ret = FAILED; 236722032991SBart Van Assche srp_free_req(target, req, scmnd, 0); 2368d945e1dfSRoland Dreier scmnd->result = DID_ABORT << 16; 2369d8536670SBart Van Assche scmnd->scsi_done(scmnd); 2370d945e1dfSRoland Dreier 2371086f44f5SBart Van Assche return ret; 2372aef9ec39SRoland Dreier } 2373aef9ec39SRoland Dreier 2374aef9ec39SRoland Dreier static int srp_reset_device(struct scsi_cmnd *scmnd) 2375aef9ec39SRoland Dreier { 2376d945e1dfSRoland Dreier struct srp_target_port *target = host_to_target(scmnd->device->host); 2377536ae14eSBart Van Assche int i; 2378d945e1dfSRoland Dreier 23797aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, "SRP reset_device called\n"); 2380aef9ec39SRoland Dreier 2381f8b6e31eSDavid Dillow if (srp_send_tsk_mgmt(target, SRP_TAG_NO_REQ, scmnd->device->lun, 2382f8b6e31eSDavid Dillow SRP_TSK_LUN_RESET)) 2383d945e1dfSRoland Dreier return FAILED; 2384f8b6e31eSDavid Dillow if (target->tsk_mgmt_status) 2385d945e1dfSRoland Dreier return FAILED; 2386d945e1dfSRoland Dreier 23874d73f95fSBart Van Assche for (i = 0; i < target->req_ring_size; ++i) { 2388536ae14eSBart Van Assche struct srp_request *req = &target->req_ring[i]; 2389b3fe628dSBart Van Assche srp_finish_req(target, req, scmnd->device, DID_RESET << 16); 2390536ae14eSBart Van Assche } 2391d945e1dfSRoland Dreier 2392d945e1dfSRoland Dreier return SUCCESS; 2393aef9ec39SRoland Dreier } 2394aef9ec39SRoland Dreier 2395aef9ec39SRoland Dreier static int srp_reset_host(struct scsi_cmnd *scmnd) 2396aef9ec39SRoland Dreier { 2397aef9ec39SRoland Dreier struct srp_target_port *target = host_to_target(scmnd->device->host); 2398aef9ec39SRoland Dreier 23997aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX "SRP reset_host called\n"); 2400aef9ec39SRoland Dreier 2401ed9b2264SBart Van Assche return srp_reconnect_rport(target->rport) == 0 ? SUCCESS : FAILED; 2402aef9ec39SRoland Dreier } 2403aef9ec39SRoland Dreier 2404c9b03c1aSBart Van Assche static int srp_slave_configure(struct scsi_device *sdev) 2405c9b03c1aSBart Van Assche { 2406c9b03c1aSBart Van Assche struct Scsi_Host *shost = sdev->host; 2407c9b03c1aSBart Van Assche struct srp_target_port *target = host_to_target(shost); 2408c9b03c1aSBart Van Assche struct request_queue *q = sdev->request_queue; 2409c9b03c1aSBart Van Assche unsigned long timeout; 2410c9b03c1aSBart Van Assche 2411c9b03c1aSBart Van Assche if (sdev->type == TYPE_DISK) { 2412c9b03c1aSBart Van Assche timeout = max_t(unsigned, 30 * HZ, target->rq_tmo_jiffies); 2413c9b03c1aSBart Van Assche blk_queue_rq_timeout(q, timeout); 2414c9b03c1aSBart Van Assche } 2415c9b03c1aSBart Van Assche 2416c9b03c1aSBart Van Assche return 0; 2417c9b03c1aSBart Van Assche } 2418c9b03c1aSBart Van Assche 2419ee959b00STony Jones static ssize_t show_id_ext(struct device *dev, struct device_attribute *attr, 2420ee959b00STony Jones char *buf) 24216ecb0c84SRoland Dreier { 2422ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 24236ecb0c84SRoland Dreier 24246ecb0c84SRoland Dreier return sprintf(buf, "0x%016llx\n", 24256ecb0c84SRoland Dreier (unsigned long long) be64_to_cpu(target->id_ext)); 24266ecb0c84SRoland Dreier } 24276ecb0c84SRoland Dreier 2428ee959b00STony Jones static ssize_t show_ioc_guid(struct device *dev, struct device_attribute *attr, 2429ee959b00STony Jones char *buf) 24306ecb0c84SRoland Dreier { 2431ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 24326ecb0c84SRoland Dreier 24336ecb0c84SRoland Dreier return sprintf(buf, "0x%016llx\n", 24346ecb0c84SRoland Dreier (unsigned long long) be64_to_cpu(target->ioc_guid)); 24356ecb0c84SRoland Dreier } 24366ecb0c84SRoland Dreier 2437ee959b00STony Jones static ssize_t show_service_id(struct device *dev, 2438ee959b00STony Jones struct device_attribute *attr, char *buf) 24396ecb0c84SRoland Dreier { 2440ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 24416ecb0c84SRoland Dreier 24426ecb0c84SRoland Dreier return sprintf(buf, "0x%016llx\n", 24436ecb0c84SRoland Dreier (unsigned long long) be64_to_cpu(target->service_id)); 24446ecb0c84SRoland Dreier } 24456ecb0c84SRoland Dreier 2446ee959b00STony Jones static ssize_t show_pkey(struct device *dev, struct device_attribute *attr, 2447ee959b00STony Jones char *buf) 24486ecb0c84SRoland Dreier { 2449ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 24506ecb0c84SRoland Dreier 24516ecb0c84SRoland Dreier return sprintf(buf, "0x%04x\n", be16_to_cpu(target->path.pkey)); 24526ecb0c84SRoland Dreier } 24536ecb0c84SRoland Dreier 2454848b3082SBart Van Assche static ssize_t show_sgid(struct device *dev, struct device_attribute *attr, 2455848b3082SBart Van Assche char *buf) 2456848b3082SBart Van Assche { 2457848b3082SBart Van Assche struct srp_target_port *target = host_to_target(class_to_shost(dev)); 2458848b3082SBart Van Assche 2459848b3082SBart Van Assche return sprintf(buf, "%pI6\n", target->path.sgid.raw); 2460848b3082SBart Van Assche } 2461848b3082SBart Van Assche 2462ee959b00STony Jones static ssize_t show_dgid(struct device *dev, struct device_attribute *attr, 2463ee959b00STony Jones char *buf) 24646ecb0c84SRoland Dreier { 2465ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 24666ecb0c84SRoland Dreier 24675b095d98SHarvey Harrison return sprintf(buf, "%pI6\n", target->path.dgid.raw); 24686ecb0c84SRoland Dreier } 24696ecb0c84SRoland Dreier 2470ee959b00STony Jones static ssize_t show_orig_dgid(struct device *dev, 2471ee959b00STony Jones struct device_attribute *attr, char *buf) 24723633b3d0SIshai Rabinovitz { 2473ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 24743633b3d0SIshai Rabinovitz 24755b095d98SHarvey Harrison return sprintf(buf, "%pI6\n", target->orig_dgid); 24763633b3d0SIshai Rabinovitz } 24773633b3d0SIshai Rabinovitz 247889de7486SBart Van Assche static ssize_t show_req_lim(struct device *dev, 247989de7486SBart Van Assche struct device_attribute *attr, char *buf) 248089de7486SBart Van Assche { 248189de7486SBart Van Assche struct srp_target_port *target = host_to_target(class_to_shost(dev)); 248289de7486SBart Van Assche 248389de7486SBart Van Assche return sprintf(buf, "%d\n", target->req_lim); 248489de7486SBart Van Assche } 248589de7486SBart Van Assche 2486ee959b00STony Jones static ssize_t show_zero_req_lim(struct device *dev, 2487ee959b00STony Jones struct device_attribute *attr, char *buf) 24886bfa24faSRoland Dreier { 2489ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 24906bfa24faSRoland Dreier 24916bfa24faSRoland Dreier return sprintf(buf, "%d\n", target->zero_req_lim); 24926bfa24faSRoland Dreier } 24936bfa24faSRoland Dreier 2494ee959b00STony Jones static ssize_t show_local_ib_port(struct device *dev, 2495ee959b00STony Jones struct device_attribute *attr, char *buf) 2496ded7f1a1SIshai Rabinovitz { 2497ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 2498ded7f1a1SIshai Rabinovitz 2499ded7f1a1SIshai Rabinovitz return sprintf(buf, "%d\n", target->srp_host->port); 2500ded7f1a1SIshai Rabinovitz } 2501ded7f1a1SIshai Rabinovitz 2502ee959b00STony Jones static ssize_t show_local_ib_device(struct device *dev, 2503ee959b00STony Jones struct device_attribute *attr, char *buf) 2504ded7f1a1SIshai Rabinovitz { 2505ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 2506ded7f1a1SIshai Rabinovitz 250705321937SGreg Kroah-Hartman return sprintf(buf, "%s\n", target->srp_host->srp_dev->dev->name); 2508ded7f1a1SIshai Rabinovitz } 2509ded7f1a1SIshai Rabinovitz 25104b5e5f41SBart Van Assche static ssize_t show_comp_vector(struct device *dev, 25114b5e5f41SBart Van Assche struct device_attribute *attr, char *buf) 25124b5e5f41SBart Van Assche { 25134b5e5f41SBart Van Assche struct srp_target_port *target = host_to_target(class_to_shost(dev)); 25144b5e5f41SBart Van Assche 25154b5e5f41SBart Van Assche return sprintf(buf, "%d\n", target->comp_vector); 25164b5e5f41SBart Van Assche } 25174b5e5f41SBart Van Assche 25187bb312e4SVu Pham static ssize_t show_tl_retry_count(struct device *dev, 25197bb312e4SVu Pham struct device_attribute *attr, char *buf) 25207bb312e4SVu Pham { 25217bb312e4SVu Pham struct srp_target_port *target = host_to_target(class_to_shost(dev)); 25227bb312e4SVu Pham 25237bb312e4SVu Pham return sprintf(buf, "%d\n", target->tl_retry_count); 25247bb312e4SVu Pham } 25257bb312e4SVu Pham 252649248644SDavid Dillow static ssize_t show_cmd_sg_entries(struct device *dev, 252749248644SDavid Dillow struct device_attribute *attr, char *buf) 252849248644SDavid Dillow { 252949248644SDavid Dillow struct srp_target_port *target = host_to_target(class_to_shost(dev)); 253049248644SDavid Dillow 253149248644SDavid Dillow return sprintf(buf, "%u\n", target->cmd_sg_cnt); 253249248644SDavid Dillow } 253349248644SDavid Dillow 2534c07d424dSDavid Dillow static ssize_t show_allow_ext_sg(struct device *dev, 2535c07d424dSDavid Dillow struct device_attribute *attr, char *buf) 2536c07d424dSDavid Dillow { 2537c07d424dSDavid Dillow struct srp_target_port *target = host_to_target(class_to_shost(dev)); 2538c07d424dSDavid Dillow 2539c07d424dSDavid Dillow return sprintf(buf, "%s\n", target->allow_ext_sg ? "true" : "false"); 2540c07d424dSDavid Dillow } 2541c07d424dSDavid Dillow 2542ee959b00STony Jones static DEVICE_ATTR(id_ext, S_IRUGO, show_id_ext, NULL); 2543ee959b00STony Jones static DEVICE_ATTR(ioc_guid, S_IRUGO, show_ioc_guid, NULL); 2544ee959b00STony Jones static DEVICE_ATTR(service_id, S_IRUGO, show_service_id, NULL); 2545ee959b00STony Jones static DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL); 2546848b3082SBart Van Assche static DEVICE_ATTR(sgid, S_IRUGO, show_sgid, NULL); 2547ee959b00STony Jones static DEVICE_ATTR(dgid, S_IRUGO, show_dgid, NULL); 2548ee959b00STony Jones static DEVICE_ATTR(orig_dgid, S_IRUGO, show_orig_dgid, NULL); 254989de7486SBart Van Assche static DEVICE_ATTR(req_lim, S_IRUGO, show_req_lim, NULL); 2550ee959b00STony Jones static DEVICE_ATTR(zero_req_lim, S_IRUGO, show_zero_req_lim, NULL); 2551ee959b00STony Jones static DEVICE_ATTR(local_ib_port, S_IRUGO, show_local_ib_port, NULL); 2552ee959b00STony Jones static DEVICE_ATTR(local_ib_device, S_IRUGO, show_local_ib_device, NULL); 25534b5e5f41SBart Van Assche static DEVICE_ATTR(comp_vector, S_IRUGO, show_comp_vector, NULL); 25547bb312e4SVu Pham static DEVICE_ATTR(tl_retry_count, S_IRUGO, show_tl_retry_count, NULL); 255549248644SDavid Dillow static DEVICE_ATTR(cmd_sg_entries, S_IRUGO, show_cmd_sg_entries, NULL); 2556c07d424dSDavid Dillow static DEVICE_ATTR(allow_ext_sg, S_IRUGO, show_allow_ext_sg, NULL); 25576ecb0c84SRoland Dreier 2558ee959b00STony Jones static struct device_attribute *srp_host_attrs[] = { 2559ee959b00STony Jones &dev_attr_id_ext, 2560ee959b00STony Jones &dev_attr_ioc_guid, 2561ee959b00STony Jones &dev_attr_service_id, 2562ee959b00STony Jones &dev_attr_pkey, 2563848b3082SBart Van Assche &dev_attr_sgid, 2564ee959b00STony Jones &dev_attr_dgid, 2565ee959b00STony Jones &dev_attr_orig_dgid, 256689de7486SBart Van Assche &dev_attr_req_lim, 2567ee959b00STony Jones &dev_attr_zero_req_lim, 2568ee959b00STony Jones &dev_attr_local_ib_port, 2569ee959b00STony Jones &dev_attr_local_ib_device, 25704b5e5f41SBart Van Assche &dev_attr_comp_vector, 25717bb312e4SVu Pham &dev_attr_tl_retry_count, 257249248644SDavid Dillow &dev_attr_cmd_sg_entries, 2573c07d424dSDavid Dillow &dev_attr_allow_ext_sg, 25746ecb0c84SRoland Dreier NULL 25756ecb0c84SRoland Dreier }; 25766ecb0c84SRoland Dreier 2577aef9ec39SRoland Dreier static struct scsi_host_template srp_template = { 2578aef9ec39SRoland Dreier .module = THIS_MODULE, 2579b7f008fdSRoland Dreier .name = "InfiniBand SRP initiator", 2580b7f008fdSRoland Dreier .proc_name = DRV_NAME, 2581c9b03c1aSBart Van Assche .slave_configure = srp_slave_configure, 2582aef9ec39SRoland Dreier .info = srp_target_info, 2583aef9ec39SRoland Dreier .queuecommand = srp_queuecommand, 258471444b97SJack Wang .change_queue_depth = srp_change_queue_depth, 2585a62182f3SChristoph Hellwig .change_queue_type = scsi_change_queue_type, 2586aef9ec39SRoland Dreier .eh_abort_handler = srp_abort, 2587aef9ec39SRoland Dreier .eh_device_reset_handler = srp_reset_device, 2588aef9ec39SRoland Dreier .eh_host_reset_handler = srp_reset_host, 25892742c1daSBart Van Assche .skip_settle_delay = true, 259049248644SDavid Dillow .sg_tablesize = SRP_DEF_SG_TABLESIZE, 25914d73f95fSBart Van Assche .can_queue = SRP_DEFAULT_CMD_SQ_SIZE, 2592aef9ec39SRoland Dreier .this_id = -1, 25934d73f95fSBart Van Assche .cmd_per_lun = SRP_DEFAULT_CMD_SQ_SIZE, 25946ecb0c84SRoland Dreier .use_clustering = ENABLE_CLUSTERING, 25956ecb0c84SRoland Dreier .shost_attrs = srp_host_attrs 2596aef9ec39SRoland Dreier }; 2597aef9ec39SRoland Dreier 2598aef9ec39SRoland Dreier static int srp_add_target(struct srp_host *host, struct srp_target_port *target) 2599aef9ec39SRoland Dreier { 26003236822bSFUJITA Tomonori struct srp_rport_identifiers ids; 26013236822bSFUJITA Tomonori struct srp_rport *rport; 26023236822bSFUJITA Tomonori 2603aef9ec39SRoland Dreier sprintf(target->target_name, "SRP.T10:%016llX", 2604aef9ec39SRoland Dreier (unsigned long long) be64_to_cpu(target->id_ext)); 2605aef9ec39SRoland Dreier 260605321937SGreg Kroah-Hartman if (scsi_add_host(target->scsi_host, host->srp_dev->dev->dma_device)) 2607aef9ec39SRoland Dreier return -ENODEV; 2608aef9ec39SRoland Dreier 26093236822bSFUJITA Tomonori memcpy(ids.port_id, &target->id_ext, 8); 26103236822bSFUJITA Tomonori memcpy(ids.port_id + 8, &target->ioc_guid, 8); 2611aebd5e47SFUJITA Tomonori ids.roles = SRP_RPORT_ROLE_TARGET; 26123236822bSFUJITA Tomonori rport = srp_rport_add(target->scsi_host, &ids); 26133236822bSFUJITA Tomonori if (IS_ERR(rport)) { 26143236822bSFUJITA Tomonori scsi_remove_host(target->scsi_host); 26153236822bSFUJITA Tomonori return PTR_ERR(rport); 26163236822bSFUJITA Tomonori } 26173236822bSFUJITA Tomonori 2618dc1bdbd9SBart Van Assche rport->lld_data = target; 26199dd69a60SBart Van Assche target->rport = rport; 2620dc1bdbd9SBart Van Assche 2621b3589fd4SMatthew Wilcox spin_lock(&host->target_lock); 2622aef9ec39SRoland Dreier list_add_tail(&target->list, &host->target_list); 2623b3589fd4SMatthew Wilcox spin_unlock(&host->target_lock); 2624aef9ec39SRoland Dreier 2625aef9ec39SRoland Dreier target->state = SRP_TARGET_LIVE; 2626aef9ec39SRoland Dreier 2627aef9ec39SRoland Dreier scsi_scan_target(&target->scsi_host->shost_gendev, 26281962a4a1SMatthew Wilcox 0, target->scsi_id, SCAN_WILD_CARD, 0); 2629aef9ec39SRoland Dreier 2630aef9ec39SRoland Dreier return 0; 2631aef9ec39SRoland Dreier } 2632aef9ec39SRoland Dreier 2633ee959b00STony Jones static void srp_release_dev(struct device *dev) 2634aef9ec39SRoland Dreier { 2635aef9ec39SRoland Dreier struct srp_host *host = 2636ee959b00STony Jones container_of(dev, struct srp_host, dev); 2637aef9ec39SRoland Dreier 2638aef9ec39SRoland Dreier complete(&host->released); 2639aef9ec39SRoland Dreier } 2640aef9ec39SRoland Dreier 2641aef9ec39SRoland Dreier static struct class srp_class = { 2642aef9ec39SRoland Dreier .name = "infiniband_srp", 2643ee959b00STony Jones .dev_release = srp_release_dev 2644aef9ec39SRoland Dreier }; 2645aef9ec39SRoland Dreier 264696fc248aSBart Van Assche /** 264796fc248aSBart Van Assche * srp_conn_unique() - check whether the connection to a target is unique 2648af24663bSBart Van Assche * @host: SRP host. 2649af24663bSBart Van Assche * @target: SRP target port. 265096fc248aSBart Van Assche */ 265196fc248aSBart Van Assche static bool srp_conn_unique(struct srp_host *host, 265296fc248aSBart Van Assche struct srp_target_port *target) 265396fc248aSBart Van Assche { 265496fc248aSBart Van Assche struct srp_target_port *t; 265596fc248aSBart Van Assche bool ret = false; 265696fc248aSBart Van Assche 265796fc248aSBart Van Assche if (target->state == SRP_TARGET_REMOVED) 265896fc248aSBart Van Assche goto out; 265996fc248aSBart Van Assche 266096fc248aSBart Van Assche ret = true; 266196fc248aSBart Van Assche 266296fc248aSBart Van Assche spin_lock(&host->target_lock); 266396fc248aSBart Van Assche list_for_each_entry(t, &host->target_list, list) { 266496fc248aSBart Van Assche if (t != target && 266596fc248aSBart Van Assche target->id_ext == t->id_ext && 266696fc248aSBart Van Assche target->ioc_guid == t->ioc_guid && 266796fc248aSBart Van Assche target->initiator_ext == t->initiator_ext) { 266896fc248aSBart Van Assche ret = false; 266996fc248aSBart Van Assche break; 267096fc248aSBart Van Assche } 267196fc248aSBart Van Assche } 267296fc248aSBart Van Assche spin_unlock(&host->target_lock); 267396fc248aSBart Van Assche 267496fc248aSBart Van Assche out: 267596fc248aSBart Van Assche return ret; 267696fc248aSBart Van Assche } 267796fc248aSBart Van Assche 2678aef9ec39SRoland Dreier /* 2679aef9ec39SRoland Dreier * Target ports are added by writing 2680aef9ec39SRoland Dreier * 2681aef9ec39SRoland Dreier * id_ext=<SRP ID ext>,ioc_guid=<SRP IOC GUID>,dgid=<dest GID>, 2682aef9ec39SRoland Dreier * pkey=<P_Key>,service_id=<service ID> 2683aef9ec39SRoland Dreier * 2684aef9ec39SRoland Dreier * to the add_target sysfs attribute. 2685aef9ec39SRoland Dreier */ 2686aef9ec39SRoland Dreier enum { 2687aef9ec39SRoland Dreier SRP_OPT_ERR = 0, 2688aef9ec39SRoland Dreier SRP_OPT_ID_EXT = 1 << 0, 2689aef9ec39SRoland Dreier SRP_OPT_IOC_GUID = 1 << 1, 2690aef9ec39SRoland Dreier SRP_OPT_DGID = 1 << 2, 2691aef9ec39SRoland Dreier SRP_OPT_PKEY = 1 << 3, 2692aef9ec39SRoland Dreier SRP_OPT_SERVICE_ID = 1 << 4, 2693aef9ec39SRoland Dreier SRP_OPT_MAX_SECT = 1 << 5, 269452fb2b50SVu Pham SRP_OPT_MAX_CMD_PER_LUN = 1 << 6, 26950c0450dbSRamachandra K SRP_OPT_IO_CLASS = 1 << 7, 269601cb9bcbSIshai Rabinovitz SRP_OPT_INITIATOR_EXT = 1 << 8, 269749248644SDavid Dillow SRP_OPT_CMD_SG_ENTRIES = 1 << 9, 2698c07d424dSDavid Dillow SRP_OPT_ALLOW_EXT_SG = 1 << 10, 2699c07d424dSDavid Dillow SRP_OPT_SG_TABLESIZE = 1 << 11, 27004b5e5f41SBart Van Assche SRP_OPT_COMP_VECTOR = 1 << 12, 27017bb312e4SVu Pham SRP_OPT_TL_RETRY_COUNT = 1 << 13, 27024d73f95fSBart Van Assche SRP_OPT_QUEUE_SIZE = 1 << 14, 2703aef9ec39SRoland Dreier SRP_OPT_ALL = (SRP_OPT_ID_EXT | 2704aef9ec39SRoland Dreier SRP_OPT_IOC_GUID | 2705aef9ec39SRoland Dreier SRP_OPT_DGID | 2706aef9ec39SRoland Dreier SRP_OPT_PKEY | 2707aef9ec39SRoland Dreier SRP_OPT_SERVICE_ID), 2708aef9ec39SRoland Dreier }; 2709aef9ec39SRoland Dreier 2710a447c093SSteven Whitehouse static const match_table_t srp_opt_tokens = { 2711aef9ec39SRoland Dreier { SRP_OPT_ID_EXT, "id_ext=%s" }, 2712aef9ec39SRoland Dreier { SRP_OPT_IOC_GUID, "ioc_guid=%s" }, 2713aef9ec39SRoland Dreier { SRP_OPT_DGID, "dgid=%s" }, 2714aef9ec39SRoland Dreier { SRP_OPT_PKEY, "pkey=%x" }, 2715aef9ec39SRoland Dreier { SRP_OPT_SERVICE_ID, "service_id=%s" }, 2716aef9ec39SRoland Dreier { SRP_OPT_MAX_SECT, "max_sect=%d" }, 271752fb2b50SVu Pham { SRP_OPT_MAX_CMD_PER_LUN, "max_cmd_per_lun=%d" }, 27180c0450dbSRamachandra K { SRP_OPT_IO_CLASS, "io_class=%x" }, 271901cb9bcbSIshai Rabinovitz { SRP_OPT_INITIATOR_EXT, "initiator_ext=%s" }, 272049248644SDavid Dillow { SRP_OPT_CMD_SG_ENTRIES, "cmd_sg_entries=%u" }, 2721c07d424dSDavid Dillow { SRP_OPT_ALLOW_EXT_SG, "allow_ext_sg=%u" }, 2722c07d424dSDavid Dillow { SRP_OPT_SG_TABLESIZE, "sg_tablesize=%u" }, 27234b5e5f41SBart Van Assche { SRP_OPT_COMP_VECTOR, "comp_vector=%u" }, 27247bb312e4SVu Pham { SRP_OPT_TL_RETRY_COUNT, "tl_retry_count=%u" }, 27254d73f95fSBart Van Assche { SRP_OPT_QUEUE_SIZE, "queue_size=%d" }, 2726aef9ec39SRoland Dreier { SRP_OPT_ERR, NULL } 2727aef9ec39SRoland Dreier }; 2728aef9ec39SRoland Dreier 2729aef9ec39SRoland Dreier static int srp_parse_options(const char *buf, struct srp_target_port *target) 2730aef9ec39SRoland Dreier { 2731aef9ec39SRoland Dreier char *options, *sep_opt; 2732aef9ec39SRoland Dreier char *p; 2733aef9ec39SRoland Dreier char dgid[3]; 2734aef9ec39SRoland Dreier substring_t args[MAX_OPT_ARGS]; 2735aef9ec39SRoland Dreier int opt_mask = 0; 2736aef9ec39SRoland Dreier int token; 2737aef9ec39SRoland Dreier int ret = -EINVAL; 2738aef9ec39SRoland Dreier int i; 2739aef9ec39SRoland Dreier 2740aef9ec39SRoland Dreier options = kstrdup(buf, GFP_KERNEL); 2741aef9ec39SRoland Dreier if (!options) 2742aef9ec39SRoland Dreier return -ENOMEM; 2743aef9ec39SRoland Dreier 2744aef9ec39SRoland Dreier sep_opt = options; 2745aef9ec39SRoland Dreier while ((p = strsep(&sep_opt, ",")) != NULL) { 2746aef9ec39SRoland Dreier if (!*p) 2747aef9ec39SRoland Dreier continue; 2748aef9ec39SRoland Dreier 2749aef9ec39SRoland Dreier token = match_token(p, srp_opt_tokens, args); 2750aef9ec39SRoland Dreier opt_mask |= token; 2751aef9ec39SRoland Dreier 2752aef9ec39SRoland Dreier switch (token) { 2753aef9ec39SRoland Dreier case SRP_OPT_ID_EXT: 2754aef9ec39SRoland Dreier p = match_strdup(args); 2755a20f3a6dSIshai Rabinovitz if (!p) { 2756a20f3a6dSIshai Rabinovitz ret = -ENOMEM; 2757a20f3a6dSIshai Rabinovitz goto out; 2758a20f3a6dSIshai Rabinovitz } 2759aef9ec39SRoland Dreier target->id_ext = cpu_to_be64(simple_strtoull(p, NULL, 16)); 2760aef9ec39SRoland Dreier kfree(p); 2761aef9ec39SRoland Dreier break; 2762aef9ec39SRoland Dreier 2763aef9ec39SRoland Dreier case SRP_OPT_IOC_GUID: 2764aef9ec39SRoland Dreier p = match_strdup(args); 2765a20f3a6dSIshai Rabinovitz if (!p) { 2766a20f3a6dSIshai Rabinovitz ret = -ENOMEM; 2767a20f3a6dSIshai Rabinovitz goto out; 2768a20f3a6dSIshai Rabinovitz } 2769aef9ec39SRoland Dreier target->ioc_guid = cpu_to_be64(simple_strtoull(p, NULL, 16)); 2770aef9ec39SRoland Dreier kfree(p); 2771aef9ec39SRoland Dreier break; 2772aef9ec39SRoland Dreier 2773aef9ec39SRoland Dreier case SRP_OPT_DGID: 2774aef9ec39SRoland Dreier p = match_strdup(args); 2775a20f3a6dSIshai Rabinovitz if (!p) { 2776a20f3a6dSIshai Rabinovitz ret = -ENOMEM; 2777a20f3a6dSIshai Rabinovitz goto out; 2778a20f3a6dSIshai Rabinovitz } 2779aef9ec39SRoland Dreier if (strlen(p) != 32) { 2780e0bda7d8SBart Van Assche pr_warn("bad dest GID parameter '%s'\n", p); 2781ce1823f0SRoland Dreier kfree(p); 2782aef9ec39SRoland Dreier goto out; 2783aef9ec39SRoland Dreier } 2784aef9ec39SRoland Dreier 2785aef9ec39SRoland Dreier for (i = 0; i < 16; ++i) { 2786aef9ec39SRoland Dreier strlcpy(dgid, p + i * 2, 3); 2787aef9ec39SRoland Dreier target->path.dgid.raw[i] = simple_strtoul(dgid, NULL, 16); 2788aef9ec39SRoland Dreier } 2789bf17c1c7SRoland Dreier kfree(p); 27903633b3d0SIshai Rabinovitz memcpy(target->orig_dgid, target->path.dgid.raw, 16); 2791aef9ec39SRoland Dreier break; 2792aef9ec39SRoland Dreier 2793aef9ec39SRoland Dreier case SRP_OPT_PKEY: 2794aef9ec39SRoland Dreier if (match_hex(args, &token)) { 2795e0bda7d8SBart Van Assche pr_warn("bad P_Key parameter '%s'\n", p); 2796aef9ec39SRoland Dreier goto out; 2797aef9ec39SRoland Dreier } 2798aef9ec39SRoland Dreier target->path.pkey = cpu_to_be16(token); 2799aef9ec39SRoland Dreier break; 2800aef9ec39SRoland Dreier 2801aef9ec39SRoland Dreier case SRP_OPT_SERVICE_ID: 2802aef9ec39SRoland Dreier p = match_strdup(args); 2803a20f3a6dSIshai Rabinovitz if (!p) { 2804a20f3a6dSIshai Rabinovitz ret = -ENOMEM; 2805a20f3a6dSIshai Rabinovitz goto out; 2806a20f3a6dSIshai Rabinovitz } 2807aef9ec39SRoland Dreier target->service_id = cpu_to_be64(simple_strtoull(p, NULL, 16)); 2808247e020eSSean Hefty target->path.service_id = target->service_id; 2809aef9ec39SRoland Dreier kfree(p); 2810aef9ec39SRoland Dreier break; 2811aef9ec39SRoland Dreier 2812aef9ec39SRoland Dreier case SRP_OPT_MAX_SECT: 2813aef9ec39SRoland Dreier if (match_int(args, &token)) { 2814e0bda7d8SBart Van Assche pr_warn("bad max sect parameter '%s'\n", p); 2815aef9ec39SRoland Dreier goto out; 2816aef9ec39SRoland Dreier } 2817aef9ec39SRoland Dreier target->scsi_host->max_sectors = token; 2818aef9ec39SRoland Dreier break; 2819aef9ec39SRoland Dreier 28204d73f95fSBart Van Assche case SRP_OPT_QUEUE_SIZE: 28214d73f95fSBart Van Assche if (match_int(args, &token) || token < 1) { 28224d73f95fSBart Van Assche pr_warn("bad queue_size parameter '%s'\n", p); 28234d73f95fSBart Van Assche goto out; 28244d73f95fSBart Van Assche } 28254d73f95fSBart Van Assche target->scsi_host->can_queue = token; 28264d73f95fSBart Van Assche target->queue_size = token + SRP_RSP_SQ_SIZE + 28274d73f95fSBart Van Assche SRP_TSK_MGMT_SQ_SIZE; 28284d73f95fSBart Van Assche if (!(opt_mask & SRP_OPT_MAX_CMD_PER_LUN)) 28294d73f95fSBart Van Assche target->scsi_host->cmd_per_lun = token; 28304d73f95fSBart Van Assche break; 28314d73f95fSBart Van Assche 283252fb2b50SVu Pham case SRP_OPT_MAX_CMD_PER_LUN: 28334d73f95fSBart Van Assche if (match_int(args, &token) || token < 1) { 2834e0bda7d8SBart Van Assche pr_warn("bad max cmd_per_lun parameter '%s'\n", 2835e0bda7d8SBart Van Assche p); 283652fb2b50SVu Pham goto out; 283752fb2b50SVu Pham } 28384d73f95fSBart Van Assche target->scsi_host->cmd_per_lun = token; 283952fb2b50SVu Pham break; 284052fb2b50SVu Pham 28410c0450dbSRamachandra K case SRP_OPT_IO_CLASS: 28420c0450dbSRamachandra K if (match_hex(args, &token)) { 2843e0bda7d8SBart Van Assche pr_warn("bad IO class parameter '%s'\n", p); 28440c0450dbSRamachandra K goto out; 28450c0450dbSRamachandra K } 28460c0450dbSRamachandra K if (token != SRP_REV10_IB_IO_CLASS && 28470c0450dbSRamachandra K token != SRP_REV16A_IB_IO_CLASS) { 2848e0bda7d8SBart Van Assche pr_warn("unknown IO class parameter value %x specified (use %x or %x).\n", 2849e0bda7d8SBart Van Assche token, SRP_REV10_IB_IO_CLASS, 2850e0bda7d8SBart Van Assche SRP_REV16A_IB_IO_CLASS); 28510c0450dbSRamachandra K goto out; 28520c0450dbSRamachandra K } 28530c0450dbSRamachandra K target->io_class = token; 28540c0450dbSRamachandra K break; 28550c0450dbSRamachandra K 285601cb9bcbSIshai Rabinovitz case SRP_OPT_INITIATOR_EXT: 285701cb9bcbSIshai Rabinovitz p = match_strdup(args); 2858a20f3a6dSIshai Rabinovitz if (!p) { 2859a20f3a6dSIshai Rabinovitz ret = -ENOMEM; 2860a20f3a6dSIshai Rabinovitz goto out; 2861a20f3a6dSIshai Rabinovitz } 286201cb9bcbSIshai Rabinovitz target->initiator_ext = cpu_to_be64(simple_strtoull(p, NULL, 16)); 286301cb9bcbSIshai Rabinovitz kfree(p); 286401cb9bcbSIshai Rabinovitz break; 286501cb9bcbSIshai Rabinovitz 286649248644SDavid Dillow case SRP_OPT_CMD_SG_ENTRIES: 286749248644SDavid Dillow if (match_int(args, &token) || token < 1 || token > 255) { 2868e0bda7d8SBart Van Assche pr_warn("bad max cmd_sg_entries parameter '%s'\n", 2869e0bda7d8SBart Van Assche p); 287049248644SDavid Dillow goto out; 287149248644SDavid Dillow } 287249248644SDavid Dillow target->cmd_sg_cnt = token; 287349248644SDavid Dillow break; 287449248644SDavid Dillow 2875c07d424dSDavid Dillow case SRP_OPT_ALLOW_EXT_SG: 2876c07d424dSDavid Dillow if (match_int(args, &token)) { 2877e0bda7d8SBart Van Assche pr_warn("bad allow_ext_sg parameter '%s'\n", p); 2878c07d424dSDavid Dillow goto out; 2879c07d424dSDavid Dillow } 2880c07d424dSDavid Dillow target->allow_ext_sg = !!token; 2881c07d424dSDavid Dillow break; 2882c07d424dSDavid Dillow 2883c07d424dSDavid Dillow case SRP_OPT_SG_TABLESIZE: 2884c07d424dSDavid Dillow if (match_int(args, &token) || token < 1 || 2885c07d424dSDavid Dillow token > SCSI_MAX_SG_CHAIN_SEGMENTS) { 2886e0bda7d8SBart Van Assche pr_warn("bad max sg_tablesize parameter '%s'\n", 2887e0bda7d8SBart Van Assche p); 2888c07d424dSDavid Dillow goto out; 2889c07d424dSDavid Dillow } 2890c07d424dSDavid Dillow target->sg_tablesize = token; 2891c07d424dSDavid Dillow break; 2892c07d424dSDavid Dillow 28934b5e5f41SBart Van Assche case SRP_OPT_COMP_VECTOR: 28944b5e5f41SBart Van Assche if (match_int(args, &token) || token < 0) { 28954b5e5f41SBart Van Assche pr_warn("bad comp_vector parameter '%s'\n", p); 28964b5e5f41SBart Van Assche goto out; 28974b5e5f41SBart Van Assche } 28984b5e5f41SBart Van Assche target->comp_vector = token; 28994b5e5f41SBart Van Assche break; 29004b5e5f41SBart Van Assche 29017bb312e4SVu Pham case SRP_OPT_TL_RETRY_COUNT: 29027bb312e4SVu Pham if (match_int(args, &token) || token < 2 || token > 7) { 29037bb312e4SVu Pham pr_warn("bad tl_retry_count parameter '%s' (must be a number between 2 and 7)\n", 29047bb312e4SVu Pham p); 29057bb312e4SVu Pham goto out; 29067bb312e4SVu Pham } 29077bb312e4SVu Pham target->tl_retry_count = token; 29087bb312e4SVu Pham break; 29097bb312e4SVu Pham 2910aef9ec39SRoland Dreier default: 2911e0bda7d8SBart Van Assche pr_warn("unknown parameter or missing value '%s' in target creation request\n", 2912e0bda7d8SBart Van Assche p); 2913aef9ec39SRoland Dreier goto out; 2914aef9ec39SRoland Dreier } 2915aef9ec39SRoland Dreier } 2916aef9ec39SRoland Dreier 2917aef9ec39SRoland Dreier if ((opt_mask & SRP_OPT_ALL) == SRP_OPT_ALL) 2918aef9ec39SRoland Dreier ret = 0; 2919aef9ec39SRoland Dreier else 2920aef9ec39SRoland Dreier for (i = 0; i < ARRAY_SIZE(srp_opt_tokens); ++i) 2921aef9ec39SRoland Dreier if ((srp_opt_tokens[i].token & SRP_OPT_ALL) && 2922aef9ec39SRoland Dreier !(srp_opt_tokens[i].token & opt_mask)) 2923e0bda7d8SBart Van Assche pr_warn("target creation request is missing parameter '%s'\n", 2924aef9ec39SRoland Dreier srp_opt_tokens[i].pattern); 2925aef9ec39SRoland Dreier 29264d73f95fSBart Van Assche if (target->scsi_host->cmd_per_lun > target->scsi_host->can_queue 29274d73f95fSBart Van Assche && (opt_mask & SRP_OPT_MAX_CMD_PER_LUN)) 29284d73f95fSBart Van Assche pr_warn("cmd_per_lun = %d > queue_size = %d\n", 29294d73f95fSBart Van Assche target->scsi_host->cmd_per_lun, 29304d73f95fSBart Van Assche target->scsi_host->can_queue); 29314d73f95fSBart Van Assche 2932aef9ec39SRoland Dreier out: 2933aef9ec39SRoland Dreier kfree(options); 2934aef9ec39SRoland Dreier return ret; 2935aef9ec39SRoland Dreier } 2936aef9ec39SRoland Dreier 2937ee959b00STony Jones static ssize_t srp_create_target(struct device *dev, 2938ee959b00STony Jones struct device_attribute *attr, 2939aef9ec39SRoland Dreier const char *buf, size_t count) 2940aef9ec39SRoland Dreier { 2941aef9ec39SRoland Dreier struct srp_host *host = 2942ee959b00STony Jones container_of(dev, struct srp_host, dev); 2943aef9ec39SRoland Dreier struct Scsi_Host *target_host; 2944aef9ec39SRoland Dreier struct srp_target_port *target; 2945d1b4289eSBart Van Assche struct srp_device *srp_dev = host->srp_dev; 2946d1b4289eSBart Van Assche struct ib_device *ibdev = srp_dev->dev; 2947b81d00bdSBart Van Assche int ret; 2948aef9ec39SRoland Dreier 2949aef9ec39SRoland Dreier target_host = scsi_host_alloc(&srp_template, 2950aef9ec39SRoland Dreier sizeof (struct srp_target_port)); 2951aef9ec39SRoland Dreier if (!target_host) 2952aef9ec39SRoland Dreier return -ENOMEM; 2953aef9ec39SRoland Dreier 29543236822bSFUJITA Tomonori target_host->transportt = ib_srp_transport_template; 2955fd1b6c4aSBart Van Assche target_host->max_channel = 0; 2956fd1b6c4aSBart Van Assche target_host->max_id = 1; 29575f068992SRoland Dreier target_host->max_lun = SRP_MAX_LUN; 29583c8edf0eSArne Redlich target_host->max_cmd_len = sizeof ((struct srp_cmd *) (void *) 0L)->cdb; 29595f068992SRoland Dreier 2960aef9ec39SRoland Dreier target = host_to_target(target_host); 2961aef9ec39SRoland Dreier 29620c0450dbSRamachandra K target->io_class = SRP_REV16A_IB_IO_CLASS; 2963aef9ec39SRoland Dreier target->scsi_host = target_host; 2964aef9ec39SRoland Dreier target->srp_host = host; 29659af76271SDavid Dillow target->lkey = host->srp_dev->mr->lkey; 29669af76271SDavid Dillow target->rkey = host->srp_dev->mr->rkey; 296749248644SDavid Dillow target->cmd_sg_cnt = cmd_sg_entries; 2968c07d424dSDavid Dillow target->sg_tablesize = indirect_sg_entries ? : cmd_sg_entries; 2969c07d424dSDavid Dillow target->allow_ext_sg = allow_ext_sg; 29707bb312e4SVu Pham target->tl_retry_count = 7; 29714d73f95fSBart Van Assche target->queue_size = SRP_DEFAULT_QUEUE_SIZE; 2972aef9ec39SRoland Dreier 29732d7091bcSBart Van Assche mutex_lock(&host->add_target_mutex); 29742d7091bcSBart Van Assche 2975aef9ec39SRoland Dreier ret = srp_parse_options(buf, target); 2976aef9ec39SRoland Dreier if (ret) 2977aef9ec39SRoland Dreier goto err; 2978aef9ec39SRoland Dreier 29794d73f95fSBart Van Assche target->req_ring_size = target->queue_size - SRP_TSK_MGMT_SQ_SIZE; 29804d73f95fSBart Van Assche 298196fc248aSBart Van Assche if (!srp_conn_unique(target->srp_host, target)) { 298296fc248aSBart Van Assche shost_printk(KERN_INFO, target->scsi_host, 298396fc248aSBart Van Assche PFX "Already connected to target port with id_ext=%016llx;ioc_guid=%016llx;initiator_ext=%016llx\n", 298496fc248aSBart Van Assche be64_to_cpu(target->id_ext), 298596fc248aSBart Van Assche be64_to_cpu(target->ioc_guid), 298696fc248aSBart Van Assche be64_to_cpu(target->initiator_ext)); 298796fc248aSBart Van Assche ret = -EEXIST; 298896fc248aSBart Van Assche goto err; 298996fc248aSBart Van Assche } 299096fc248aSBart Van Assche 29915cfb1782SBart Van Assche if (!srp_dev->has_fmr && !srp_dev->has_fr && !target->allow_ext_sg && 2992c07d424dSDavid Dillow target->cmd_sg_cnt < target->sg_tablesize) { 29935cfb1782SBart Van Assche pr_warn("No MR pool and no external indirect descriptors, limiting sg_tablesize to cmd_sg_cnt\n"); 2994c07d424dSDavid Dillow target->sg_tablesize = target->cmd_sg_cnt; 2995c07d424dSDavid Dillow } 2996c07d424dSDavid Dillow 2997c07d424dSDavid Dillow target_host->sg_tablesize = target->sg_tablesize; 2998c07d424dSDavid Dillow target->indirect_size = target->sg_tablesize * 2999c07d424dSDavid Dillow sizeof (struct srp_direct_buf); 300049248644SDavid Dillow target->max_iu_len = sizeof (struct srp_cmd) + 300149248644SDavid Dillow sizeof (struct srp_indirect_buf) + 300249248644SDavid Dillow target->cmd_sg_cnt * sizeof (struct srp_direct_buf); 300349248644SDavid Dillow 3004c1120f89SBart Van Assche INIT_WORK(&target->tl_err_work, srp_tl_err_work); 3005ef6c49d8SBart Van Assche INIT_WORK(&target->remove_work, srp_remove_work); 30068f26c9ffSDavid Dillow spin_lock_init(&target->lock); 30078f26c9ffSDavid Dillow INIT_LIST_HEAD(&target->free_tx); 3008b81d00bdSBart Van Assche ret = srp_alloc_req_data(target); 3009b81d00bdSBart Van Assche if (ret) 30108f26c9ffSDavid Dillow goto err_free_mem; 30118f26c9ffSDavid Dillow 30122088ca66SSagi Grimberg ret = ib_query_gid(ibdev, host->port, 0, &target->path.sgid); 30132088ca66SSagi Grimberg if (ret) 30142088ca66SSagi Grimberg goto err_free_mem; 3015aef9ec39SRoland Dreier 3016aef9ec39SRoland Dreier ret = srp_create_target_ib(target); 3017aef9ec39SRoland Dreier if (ret) 30188f26c9ffSDavid Dillow goto err_free_mem; 3019aef9ec39SRoland Dreier 30209fe4bcf4SDavid Dillow ret = srp_new_cm_id(target); 30219fe4bcf4SDavid Dillow if (ret) 30228f26c9ffSDavid Dillow goto err_free_ib; 3023aef9ec39SRoland Dreier 3024aef9ec39SRoland Dreier ret = srp_connect_target(target); 3025aef9ec39SRoland Dreier if (ret) { 30267aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 30277aa54bd7SDavid Dillow PFX "Connection failed\n"); 3028*394c595eSBart Van Assche goto err_free_ib; 3029aef9ec39SRoland Dreier } 3030aef9ec39SRoland Dreier 3031aef9ec39SRoland Dreier ret = srp_add_target(host, target); 3032aef9ec39SRoland Dreier if (ret) 3033aef9ec39SRoland Dreier goto err_disconnect; 3034aef9ec39SRoland Dreier 3035e7ffde01SBart Van Assche shost_printk(KERN_DEBUG, target->scsi_host, PFX 3036e7ffde01SBart Van Assche "new target: id_ext %016llx ioc_guid %016llx pkey %04x service_id %016llx sgid %pI6 dgid %pI6\n", 3037e7ffde01SBart Van Assche be64_to_cpu(target->id_ext), 3038e7ffde01SBart Van Assche be64_to_cpu(target->ioc_guid), 3039e7ffde01SBart Van Assche be16_to_cpu(target->path.pkey), 3040e7ffde01SBart Van Assche be64_to_cpu(target->service_id), 3041e7ffde01SBart Van Assche target->path.sgid.raw, target->path.dgid.raw); 3042e7ffde01SBart Van Assche 30432d7091bcSBart Van Assche ret = count; 30442d7091bcSBart Van Assche 30452d7091bcSBart Van Assche out: 30462d7091bcSBart Van Assche mutex_unlock(&host->add_target_mutex); 30472d7091bcSBart Van Assche return ret; 3048aef9ec39SRoland Dreier 3049aef9ec39SRoland Dreier err_disconnect: 3050aef9ec39SRoland Dreier srp_disconnect_target(target); 3051aef9ec39SRoland Dreier 30528f26c9ffSDavid Dillow err_free_ib: 3053aef9ec39SRoland Dreier srp_free_target_ib(target); 3054aef9ec39SRoland Dreier 30558f26c9ffSDavid Dillow err_free_mem: 30568f26c9ffSDavid Dillow srp_free_req_data(target); 30578f26c9ffSDavid Dillow 3058aef9ec39SRoland Dreier err: 3059aef9ec39SRoland Dreier scsi_host_put(target_host); 30602d7091bcSBart Van Assche goto out; 3061aef9ec39SRoland Dreier } 3062aef9ec39SRoland Dreier 3063ee959b00STony Jones static DEVICE_ATTR(add_target, S_IWUSR, NULL, srp_create_target); 3064aef9ec39SRoland Dreier 3065ee959b00STony Jones static ssize_t show_ibdev(struct device *dev, struct device_attribute *attr, 3066ee959b00STony Jones char *buf) 3067aef9ec39SRoland Dreier { 3068ee959b00STony Jones struct srp_host *host = container_of(dev, struct srp_host, dev); 3069aef9ec39SRoland Dreier 307005321937SGreg Kroah-Hartman return sprintf(buf, "%s\n", host->srp_dev->dev->name); 3071aef9ec39SRoland Dreier } 3072aef9ec39SRoland Dreier 3073ee959b00STony Jones static DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL); 3074aef9ec39SRoland Dreier 3075ee959b00STony Jones static ssize_t show_port(struct device *dev, struct device_attribute *attr, 3076ee959b00STony Jones char *buf) 3077aef9ec39SRoland Dreier { 3078ee959b00STony Jones struct srp_host *host = container_of(dev, struct srp_host, dev); 3079aef9ec39SRoland Dreier 3080aef9ec39SRoland Dreier return sprintf(buf, "%d\n", host->port); 3081aef9ec39SRoland Dreier } 3082aef9ec39SRoland Dreier 3083ee959b00STony Jones static DEVICE_ATTR(port, S_IRUGO, show_port, NULL); 3084aef9ec39SRoland Dreier 3085f5358a17SRoland Dreier static struct srp_host *srp_add_port(struct srp_device *device, u8 port) 3086aef9ec39SRoland Dreier { 3087aef9ec39SRoland Dreier struct srp_host *host; 3088aef9ec39SRoland Dreier 3089aef9ec39SRoland Dreier host = kzalloc(sizeof *host, GFP_KERNEL); 3090aef9ec39SRoland Dreier if (!host) 3091aef9ec39SRoland Dreier return NULL; 3092aef9ec39SRoland Dreier 3093aef9ec39SRoland Dreier INIT_LIST_HEAD(&host->target_list); 3094b3589fd4SMatthew Wilcox spin_lock_init(&host->target_lock); 3095aef9ec39SRoland Dreier init_completion(&host->released); 30962d7091bcSBart Van Assche mutex_init(&host->add_target_mutex); 309705321937SGreg Kroah-Hartman host->srp_dev = device; 3098aef9ec39SRoland Dreier host->port = port; 3099aef9ec39SRoland Dreier 3100ee959b00STony Jones host->dev.class = &srp_class; 3101ee959b00STony Jones host->dev.parent = device->dev->dma_device; 3102d927e38cSKay Sievers dev_set_name(&host->dev, "srp-%s-%d", device->dev->name, port); 3103aef9ec39SRoland Dreier 3104ee959b00STony Jones if (device_register(&host->dev)) 3105f5358a17SRoland Dreier goto free_host; 3106ee959b00STony Jones if (device_create_file(&host->dev, &dev_attr_add_target)) 3107aef9ec39SRoland Dreier goto err_class; 3108ee959b00STony Jones if (device_create_file(&host->dev, &dev_attr_ibdev)) 3109aef9ec39SRoland Dreier goto err_class; 3110ee959b00STony Jones if (device_create_file(&host->dev, &dev_attr_port)) 3111aef9ec39SRoland Dreier goto err_class; 3112aef9ec39SRoland Dreier 3113aef9ec39SRoland Dreier return host; 3114aef9ec39SRoland Dreier 3115aef9ec39SRoland Dreier err_class: 3116ee959b00STony Jones device_unregister(&host->dev); 3117aef9ec39SRoland Dreier 3118f5358a17SRoland Dreier free_host: 3119aef9ec39SRoland Dreier kfree(host); 3120aef9ec39SRoland Dreier 3121aef9ec39SRoland Dreier return NULL; 3122aef9ec39SRoland Dreier } 3123aef9ec39SRoland Dreier 3124aef9ec39SRoland Dreier static void srp_add_one(struct ib_device *device) 3125aef9ec39SRoland Dreier { 3126f5358a17SRoland Dreier struct srp_device *srp_dev; 3127f5358a17SRoland Dreier struct ib_device_attr *dev_attr; 3128aef9ec39SRoland Dreier struct srp_host *host; 312952ede08fSBart Van Assche int mr_page_shift, s, e, p; 313052ede08fSBart Van Assche u64 max_pages_per_mr; 3131aef9ec39SRoland Dreier 3132f5358a17SRoland Dreier dev_attr = kmalloc(sizeof *dev_attr, GFP_KERNEL); 3133f5358a17SRoland Dreier if (!dev_attr) 3134cf311cd4SSean Hefty return; 3135aef9ec39SRoland Dreier 3136f5358a17SRoland Dreier if (ib_query_device(device, dev_attr)) { 3137e0bda7d8SBart Van Assche pr_warn("Query device failed for %s\n", device->name); 3138f5358a17SRoland Dreier goto free_attr; 3139f5358a17SRoland Dreier } 3140f5358a17SRoland Dreier 3141f5358a17SRoland Dreier srp_dev = kmalloc(sizeof *srp_dev, GFP_KERNEL); 3142f5358a17SRoland Dreier if (!srp_dev) 3143f5358a17SRoland Dreier goto free_attr; 3144f5358a17SRoland Dreier 3145d1b4289eSBart Van Assche srp_dev->has_fmr = (device->alloc_fmr && device->dealloc_fmr && 3146d1b4289eSBart Van Assche device->map_phys_fmr && device->unmap_fmr); 31475cfb1782SBart Van Assche srp_dev->has_fr = (dev_attr->device_cap_flags & 31485cfb1782SBart Van Assche IB_DEVICE_MEM_MGT_EXTENSIONS); 31495cfb1782SBart Van Assche if (!srp_dev->has_fmr && !srp_dev->has_fr) 31505cfb1782SBart Van Assche dev_warn(&device->dev, "neither FMR nor FR is supported\n"); 31515cfb1782SBart Van Assche 31525cfb1782SBart Van Assche srp_dev->use_fast_reg = (srp_dev->has_fr && 31535cfb1782SBart Van Assche (!srp_dev->has_fmr || prefer_fr)); 3154d1b4289eSBart Van Assche 3155f5358a17SRoland Dreier /* 3156f5358a17SRoland Dreier * Use the smallest page size supported by the HCA, down to a 31578f26c9ffSDavid Dillow * minimum of 4096 bytes. We're unlikely to build large sglists 31588f26c9ffSDavid Dillow * out of smaller entries. 3159f5358a17SRoland Dreier */ 316052ede08fSBart Van Assche mr_page_shift = max(12, ffs(dev_attr->page_size_cap) - 1); 316152ede08fSBart Van Assche srp_dev->mr_page_size = 1 << mr_page_shift; 316252ede08fSBart Van Assche srp_dev->mr_page_mask = ~((u64) srp_dev->mr_page_size - 1); 316352ede08fSBart Van Assche max_pages_per_mr = dev_attr->max_mr_size; 316452ede08fSBart Van Assche do_div(max_pages_per_mr, srp_dev->mr_page_size); 316552ede08fSBart Van Assche srp_dev->max_pages_per_mr = min_t(u64, SRP_MAX_PAGES_PER_MR, 316652ede08fSBart Van Assche max_pages_per_mr); 31675cfb1782SBart Van Assche if (srp_dev->use_fast_reg) { 31685cfb1782SBart Van Assche srp_dev->max_pages_per_mr = 31695cfb1782SBart Van Assche min_t(u32, srp_dev->max_pages_per_mr, 31705cfb1782SBart Van Assche dev_attr->max_fast_reg_page_list_len); 31715cfb1782SBart Van Assche } 317252ede08fSBart Van Assche srp_dev->mr_max_size = srp_dev->mr_page_size * 317352ede08fSBart Van Assche srp_dev->max_pages_per_mr; 31745cfb1782SBart Van Assche pr_debug("%s: mr_page_shift = %d, dev_attr->max_mr_size = %#llx, dev_attr->max_fast_reg_page_list_len = %u, max_pages_per_mr = %d, mr_max_size = %#x\n", 317552ede08fSBart Van Assche device->name, mr_page_shift, dev_attr->max_mr_size, 31765cfb1782SBart Van Assche dev_attr->max_fast_reg_page_list_len, 317752ede08fSBart Van Assche srp_dev->max_pages_per_mr, srp_dev->mr_max_size); 3178f5358a17SRoland Dreier 3179f5358a17SRoland Dreier INIT_LIST_HEAD(&srp_dev->dev_list); 3180f5358a17SRoland Dreier 3181f5358a17SRoland Dreier srp_dev->dev = device; 3182f5358a17SRoland Dreier srp_dev->pd = ib_alloc_pd(device); 3183f5358a17SRoland Dreier if (IS_ERR(srp_dev->pd)) 3184f5358a17SRoland Dreier goto free_dev; 3185f5358a17SRoland Dreier 3186f5358a17SRoland Dreier srp_dev->mr = ib_get_dma_mr(srp_dev->pd, 3187f5358a17SRoland Dreier IB_ACCESS_LOCAL_WRITE | 3188f5358a17SRoland Dreier IB_ACCESS_REMOTE_READ | 3189f5358a17SRoland Dreier IB_ACCESS_REMOTE_WRITE); 3190f5358a17SRoland Dreier if (IS_ERR(srp_dev->mr)) 3191f5358a17SRoland Dreier goto err_pd; 3192f5358a17SRoland Dreier 319307ebafbaSTom Tucker if (device->node_type == RDMA_NODE_IB_SWITCH) { 3194aef9ec39SRoland Dreier s = 0; 3195aef9ec39SRoland Dreier e = 0; 3196aef9ec39SRoland Dreier } else { 3197aef9ec39SRoland Dreier s = 1; 3198aef9ec39SRoland Dreier e = device->phys_port_cnt; 3199aef9ec39SRoland Dreier } 3200aef9ec39SRoland Dreier 3201aef9ec39SRoland Dreier for (p = s; p <= e; ++p) { 3202f5358a17SRoland Dreier host = srp_add_port(srp_dev, p); 3203aef9ec39SRoland Dreier if (host) 3204f5358a17SRoland Dreier list_add_tail(&host->list, &srp_dev->dev_list); 3205aef9ec39SRoland Dreier } 3206aef9ec39SRoland Dreier 3207f5358a17SRoland Dreier ib_set_client_data(device, &srp_client, srp_dev); 3208f5358a17SRoland Dreier 3209f5358a17SRoland Dreier goto free_attr; 3210f5358a17SRoland Dreier 3211f5358a17SRoland Dreier err_pd: 3212f5358a17SRoland Dreier ib_dealloc_pd(srp_dev->pd); 3213f5358a17SRoland Dreier 3214f5358a17SRoland Dreier free_dev: 3215f5358a17SRoland Dreier kfree(srp_dev); 3216f5358a17SRoland Dreier 3217f5358a17SRoland Dreier free_attr: 3218f5358a17SRoland Dreier kfree(dev_attr); 3219aef9ec39SRoland Dreier } 3220aef9ec39SRoland Dreier 3221aef9ec39SRoland Dreier static void srp_remove_one(struct ib_device *device) 3222aef9ec39SRoland Dreier { 3223f5358a17SRoland Dreier struct srp_device *srp_dev; 3224aef9ec39SRoland Dreier struct srp_host *host, *tmp_host; 3225ef6c49d8SBart Van Assche struct srp_target_port *target; 3226aef9ec39SRoland Dreier 3227f5358a17SRoland Dreier srp_dev = ib_get_client_data(device, &srp_client); 32281fe0cb84SDotan Barak if (!srp_dev) 32291fe0cb84SDotan Barak return; 3230aef9ec39SRoland Dreier 3231f5358a17SRoland Dreier list_for_each_entry_safe(host, tmp_host, &srp_dev->dev_list, list) { 3232ee959b00STony Jones device_unregister(&host->dev); 3233aef9ec39SRoland Dreier /* 3234aef9ec39SRoland Dreier * Wait for the sysfs entry to go away, so that no new 3235aef9ec39SRoland Dreier * target ports can be created. 3236aef9ec39SRoland Dreier */ 3237aef9ec39SRoland Dreier wait_for_completion(&host->released); 3238aef9ec39SRoland Dreier 3239aef9ec39SRoland Dreier /* 3240ef6c49d8SBart Van Assche * Remove all target ports. 3241aef9ec39SRoland Dreier */ 3242b3589fd4SMatthew Wilcox spin_lock(&host->target_lock); 3243ef6c49d8SBart Van Assche list_for_each_entry(target, &host->target_list, list) 3244ef6c49d8SBart Van Assche srp_queue_remove_work(target); 3245b3589fd4SMatthew Wilcox spin_unlock(&host->target_lock); 3246aef9ec39SRoland Dreier 3247aef9ec39SRoland Dreier /* 3248bcc05910SBart Van Assche * Wait for tl_err and target port removal tasks. 3249aef9ec39SRoland Dreier */ 3250ef6c49d8SBart Van Assche flush_workqueue(system_long_wq); 3251bcc05910SBart Van Assche flush_workqueue(srp_remove_wq); 3252aef9ec39SRoland Dreier 3253aef9ec39SRoland Dreier kfree(host); 3254aef9ec39SRoland Dreier } 3255aef9ec39SRoland Dreier 3256f5358a17SRoland Dreier ib_dereg_mr(srp_dev->mr); 3257f5358a17SRoland Dreier ib_dealloc_pd(srp_dev->pd); 3258f5358a17SRoland Dreier 3259f5358a17SRoland Dreier kfree(srp_dev); 3260aef9ec39SRoland Dreier } 3261aef9ec39SRoland Dreier 32623236822bSFUJITA Tomonori static struct srp_function_template ib_srp_transport_functions = { 3263ed9b2264SBart Van Assche .has_rport_state = true, 3264ed9b2264SBart Van Assche .reset_timer_if_blocked = true, 3265a95cadb9SBart Van Assche .reconnect_delay = &srp_reconnect_delay, 3266ed9b2264SBart Van Assche .fast_io_fail_tmo = &srp_fast_io_fail_tmo, 3267ed9b2264SBart Van Assche .dev_loss_tmo = &srp_dev_loss_tmo, 3268ed9b2264SBart Van Assche .reconnect = srp_rport_reconnect, 3269dc1bdbd9SBart Van Assche .rport_delete = srp_rport_delete, 3270ed9b2264SBart Van Assche .terminate_rport_io = srp_terminate_io, 32713236822bSFUJITA Tomonori }; 32723236822bSFUJITA Tomonori 3273aef9ec39SRoland Dreier static int __init srp_init_module(void) 3274aef9ec39SRoland Dreier { 3275aef9ec39SRoland Dreier int ret; 3276aef9ec39SRoland Dreier 3277dcb4cb85SBart Van Assche BUILD_BUG_ON(FIELD_SIZEOF(struct ib_wc, wr_id) < sizeof(void *)); 3278dd5e6e38SBart Van Assche 327949248644SDavid Dillow if (srp_sg_tablesize) { 3280e0bda7d8SBart Van Assche pr_warn("srp_sg_tablesize is deprecated, please use cmd_sg_entries\n"); 328149248644SDavid Dillow if (!cmd_sg_entries) 328249248644SDavid Dillow cmd_sg_entries = srp_sg_tablesize; 328349248644SDavid Dillow } 328449248644SDavid Dillow 328549248644SDavid Dillow if (!cmd_sg_entries) 328649248644SDavid Dillow cmd_sg_entries = SRP_DEF_SG_TABLESIZE; 328749248644SDavid Dillow 328849248644SDavid Dillow if (cmd_sg_entries > 255) { 3289e0bda7d8SBart Van Assche pr_warn("Clamping cmd_sg_entries to 255\n"); 329049248644SDavid Dillow cmd_sg_entries = 255; 32911e89a194SDavid Dillow } 32921e89a194SDavid Dillow 3293c07d424dSDavid Dillow if (!indirect_sg_entries) 3294c07d424dSDavid Dillow indirect_sg_entries = cmd_sg_entries; 3295c07d424dSDavid Dillow else if (indirect_sg_entries < cmd_sg_entries) { 3296e0bda7d8SBart Van Assche pr_warn("Bumping up indirect_sg_entries to match cmd_sg_entries (%u)\n", 3297e0bda7d8SBart Van Assche cmd_sg_entries); 3298c07d424dSDavid Dillow indirect_sg_entries = cmd_sg_entries; 3299c07d424dSDavid Dillow } 3300c07d424dSDavid Dillow 3301bcc05910SBart Van Assche srp_remove_wq = create_workqueue("srp_remove"); 3302da05be29SWei Yongjun if (!srp_remove_wq) { 3303da05be29SWei Yongjun ret = -ENOMEM; 3304bcc05910SBart Van Assche goto out; 3305bcc05910SBart Van Assche } 3306bcc05910SBart Van Assche 3307bcc05910SBart Van Assche ret = -ENOMEM; 33083236822bSFUJITA Tomonori ib_srp_transport_template = 33093236822bSFUJITA Tomonori srp_attach_transport(&ib_srp_transport_functions); 33103236822bSFUJITA Tomonori if (!ib_srp_transport_template) 3311bcc05910SBart Van Assche goto destroy_wq; 33123236822bSFUJITA Tomonori 3313aef9ec39SRoland Dreier ret = class_register(&srp_class); 3314aef9ec39SRoland Dreier if (ret) { 3315e0bda7d8SBart Van Assche pr_err("couldn't register class infiniband_srp\n"); 3316bcc05910SBart Van Assche goto release_tr; 3317aef9ec39SRoland Dreier } 3318aef9ec39SRoland Dreier 3319c1a0b23bSMichael S. Tsirkin ib_sa_register_client(&srp_sa_client); 3320c1a0b23bSMichael S. Tsirkin 3321aef9ec39SRoland Dreier ret = ib_register_client(&srp_client); 3322aef9ec39SRoland Dreier if (ret) { 3323e0bda7d8SBart Van Assche pr_err("couldn't register IB client\n"); 3324bcc05910SBart Van Assche goto unreg_sa; 3325aef9ec39SRoland Dreier } 3326aef9ec39SRoland Dreier 3327bcc05910SBart Van Assche out: 3328bcc05910SBart Van Assche return ret; 3329bcc05910SBart Van Assche 3330bcc05910SBart Van Assche unreg_sa: 3331bcc05910SBart Van Assche ib_sa_unregister_client(&srp_sa_client); 3332bcc05910SBart Van Assche class_unregister(&srp_class); 3333bcc05910SBart Van Assche 3334bcc05910SBart Van Assche release_tr: 3335bcc05910SBart Van Assche srp_release_transport(ib_srp_transport_template); 3336bcc05910SBart Van Assche 3337bcc05910SBart Van Assche destroy_wq: 3338bcc05910SBart Van Assche destroy_workqueue(srp_remove_wq); 3339bcc05910SBart Van Assche goto out; 3340aef9ec39SRoland Dreier } 3341aef9ec39SRoland Dreier 3342aef9ec39SRoland Dreier static void __exit srp_cleanup_module(void) 3343aef9ec39SRoland Dreier { 3344aef9ec39SRoland Dreier ib_unregister_client(&srp_client); 3345c1a0b23bSMichael S. Tsirkin ib_sa_unregister_client(&srp_sa_client); 3346aef9ec39SRoland Dreier class_unregister(&srp_class); 33473236822bSFUJITA Tomonori srp_release_transport(ib_srp_transport_template); 3348bcc05910SBart Van Assche destroy_workqueue(srp_remove_wq); 3349aef9ec39SRoland Dreier } 3350aef9ec39SRoland Dreier 3351aef9ec39SRoland Dreier module_init(srp_init_module); 3352aef9ec39SRoland Dreier module_exit(srp_cleanup_module); 3353