162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2005 Cisco Systems. All rights reserved. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * This software is available to you under a choice of one of two 562306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 662306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 762306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 862306a36Sopenharmony_ci * OpenIB.org BSD license below: 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1162306a36Sopenharmony_ci * without modification, are permitted provided that the following 1262306a36Sopenharmony_ci * conditions are met: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1562306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1662306a36Sopenharmony_ci * disclaimer. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 1962306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2062306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2162306a36Sopenharmony_ci * provided with the distribution. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2462306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2562306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2662306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2762306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 2862306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 2962306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3062306a36Sopenharmony_ci * SOFTWARE. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#include <linux/module.h> 3662306a36Sopenharmony_ci#include <linux/init.h> 3762306a36Sopenharmony_ci#include <linux/slab.h> 3862306a36Sopenharmony_ci#include <linux/err.h> 3962306a36Sopenharmony_ci#include <linux/string.h> 4062306a36Sopenharmony_ci#include <linux/parser.h> 4162306a36Sopenharmony_ci#include <linux/random.h> 4262306a36Sopenharmony_ci#include <linux/jiffies.h> 4362306a36Sopenharmony_ci#include <linux/lockdep.h> 4462306a36Sopenharmony_ci#include <linux/inet.h> 4562306a36Sopenharmony_ci#include <rdma/ib_cache.h> 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#include <linux/atomic.h> 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#include <scsi/scsi.h> 5062306a36Sopenharmony_ci#include <scsi/scsi_device.h> 5162306a36Sopenharmony_ci#include <scsi/scsi_dbg.h> 5262306a36Sopenharmony_ci#include <scsi/scsi_tcq.h> 5362306a36Sopenharmony_ci#include <scsi/srp.h> 5462306a36Sopenharmony_ci#include <scsi/scsi_transport_srp.h> 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#include "ib_srp.h" 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#define DRV_NAME "ib_srp" 5962306a36Sopenharmony_ci#define PFX DRV_NAME ": " 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ciMODULE_AUTHOR("Roland Dreier"); 6262306a36Sopenharmony_ciMODULE_DESCRIPTION("InfiniBand SCSI RDMA Protocol initiator"); 6362306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic unsigned int srp_sg_tablesize; 6662306a36Sopenharmony_cistatic unsigned int cmd_sg_entries; 6762306a36Sopenharmony_cistatic unsigned int indirect_sg_entries; 6862306a36Sopenharmony_cistatic bool allow_ext_sg; 6962306a36Sopenharmony_cistatic bool register_always = true; 7062306a36Sopenharmony_cistatic bool never_register; 7162306a36Sopenharmony_cistatic int topspin_workarounds = 1; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cimodule_param(srp_sg_tablesize, uint, 0444); 7462306a36Sopenharmony_ciMODULE_PARM_DESC(srp_sg_tablesize, "Deprecated name for cmd_sg_entries"); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cimodule_param(cmd_sg_entries, uint, 0444); 7762306a36Sopenharmony_ciMODULE_PARM_DESC(cmd_sg_entries, 7862306a36Sopenharmony_ci "Default number of gather/scatter entries in the SRP command (default is 12, max 255)"); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cimodule_param(indirect_sg_entries, uint, 0444); 8162306a36Sopenharmony_ciMODULE_PARM_DESC(indirect_sg_entries, 8262306a36Sopenharmony_ci "Default max number of gather/scatter entries (default is 12, max is " __stringify(SG_MAX_SEGMENTS) ")"); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cimodule_param(allow_ext_sg, bool, 0444); 8562306a36Sopenharmony_ciMODULE_PARM_DESC(allow_ext_sg, 8662306a36Sopenharmony_ci "Default behavior when there are more than cmd_sg_entries S/G entries after mapping; fails the request when false (default false)"); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cimodule_param(topspin_workarounds, int, 0444); 8962306a36Sopenharmony_ciMODULE_PARM_DESC(topspin_workarounds, 9062306a36Sopenharmony_ci "Enable workarounds for Topspin/Cisco SRP target bugs if != 0"); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cimodule_param(register_always, bool, 0444); 9362306a36Sopenharmony_ciMODULE_PARM_DESC(register_always, 9462306a36Sopenharmony_ci "Use memory registration even for contiguous memory regions"); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cimodule_param(never_register, bool, 0444); 9762306a36Sopenharmony_ciMODULE_PARM_DESC(never_register, "Never register memory"); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic const struct kernel_param_ops srp_tmo_ops; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic int srp_reconnect_delay = 10; 10262306a36Sopenharmony_cimodule_param_cb(reconnect_delay, &srp_tmo_ops, &srp_reconnect_delay, 10362306a36Sopenharmony_ci S_IRUGO | S_IWUSR); 10462306a36Sopenharmony_ciMODULE_PARM_DESC(reconnect_delay, "Time between successive reconnect attempts"); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic int srp_fast_io_fail_tmo = 15; 10762306a36Sopenharmony_cimodule_param_cb(fast_io_fail_tmo, &srp_tmo_ops, &srp_fast_io_fail_tmo, 10862306a36Sopenharmony_ci S_IRUGO | S_IWUSR); 10962306a36Sopenharmony_ciMODULE_PARM_DESC(fast_io_fail_tmo, 11062306a36Sopenharmony_ci "Number of seconds between the observation of a transport" 11162306a36Sopenharmony_ci " layer error and failing all I/O. \"off\" means that this" 11262306a36Sopenharmony_ci " functionality is disabled."); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic int srp_dev_loss_tmo = 600; 11562306a36Sopenharmony_cimodule_param_cb(dev_loss_tmo, &srp_tmo_ops, &srp_dev_loss_tmo, 11662306a36Sopenharmony_ci S_IRUGO | S_IWUSR); 11762306a36Sopenharmony_ciMODULE_PARM_DESC(dev_loss_tmo, 11862306a36Sopenharmony_ci "Maximum number of seconds that the SRP transport should" 11962306a36Sopenharmony_ci " insulate transport layer errors. After this time has been" 12062306a36Sopenharmony_ci " exceeded the SCSI host is removed. Should be" 12162306a36Sopenharmony_ci " between 1 and " __stringify(SCSI_DEVICE_BLOCK_MAX_TIMEOUT) 12262306a36Sopenharmony_ci " if fast_io_fail_tmo has not been set. \"off\" means that" 12362306a36Sopenharmony_ci " this functionality is disabled."); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic bool srp_use_imm_data = true; 12662306a36Sopenharmony_cimodule_param_named(use_imm_data, srp_use_imm_data, bool, 0644); 12762306a36Sopenharmony_ciMODULE_PARM_DESC(use_imm_data, 12862306a36Sopenharmony_ci "Whether or not to request permission to use immediate data during SRP login."); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic unsigned int srp_max_imm_data = 8 * 1024; 13162306a36Sopenharmony_cimodule_param_named(max_imm_data, srp_max_imm_data, uint, 0644); 13262306a36Sopenharmony_ciMODULE_PARM_DESC(max_imm_data, "Maximum immediate data size."); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic unsigned ch_count; 13562306a36Sopenharmony_cimodule_param(ch_count, uint, 0444); 13662306a36Sopenharmony_ciMODULE_PARM_DESC(ch_count, 13762306a36Sopenharmony_ci "Number of RDMA channels to use for communication with an SRP target. Using more than one channel improves performance if the HCA supports multiple completion vectors. The default value is the minimum of four times the number of online CPU sockets and the number of completion vectors supported by the HCA."); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic int srp_add_one(struct ib_device *device); 14062306a36Sopenharmony_cistatic void srp_remove_one(struct ib_device *device, void *client_data); 14162306a36Sopenharmony_cistatic void srp_rename_dev(struct ib_device *device, void *client_data); 14262306a36Sopenharmony_cistatic void srp_recv_done(struct ib_cq *cq, struct ib_wc *wc); 14362306a36Sopenharmony_cistatic void srp_handle_qp_err(struct ib_cq *cq, struct ib_wc *wc, 14462306a36Sopenharmony_ci const char *opname); 14562306a36Sopenharmony_cistatic int srp_ib_cm_handler(struct ib_cm_id *cm_id, 14662306a36Sopenharmony_ci const struct ib_cm_event *event); 14762306a36Sopenharmony_cistatic int srp_rdma_cm_handler(struct rdma_cm_id *cm_id, 14862306a36Sopenharmony_ci struct rdma_cm_event *event); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic struct scsi_transport_template *ib_srp_transport_template; 15162306a36Sopenharmony_cistatic struct workqueue_struct *srp_remove_wq; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic struct ib_client srp_client = { 15462306a36Sopenharmony_ci .name = "srp", 15562306a36Sopenharmony_ci .add = srp_add_one, 15662306a36Sopenharmony_ci .remove = srp_remove_one, 15762306a36Sopenharmony_ci .rename = srp_rename_dev 15862306a36Sopenharmony_ci}; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic struct ib_sa_client srp_sa_client; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic int srp_tmo_get(char *buffer, const struct kernel_param *kp) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci int tmo = *(int *)kp->arg; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci if (tmo >= 0) 16762306a36Sopenharmony_ci return sysfs_emit(buffer, "%d\n", tmo); 16862306a36Sopenharmony_ci else 16962306a36Sopenharmony_ci return sysfs_emit(buffer, "off\n"); 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic int srp_tmo_set(const char *val, const struct kernel_param *kp) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci int tmo, res; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci res = srp_parse_tmo(&tmo, val); 17762306a36Sopenharmony_ci if (res) 17862306a36Sopenharmony_ci goto out; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci if (kp->arg == &srp_reconnect_delay) 18162306a36Sopenharmony_ci res = srp_tmo_valid(tmo, srp_fast_io_fail_tmo, 18262306a36Sopenharmony_ci srp_dev_loss_tmo); 18362306a36Sopenharmony_ci else if (kp->arg == &srp_fast_io_fail_tmo) 18462306a36Sopenharmony_ci res = srp_tmo_valid(srp_reconnect_delay, tmo, srp_dev_loss_tmo); 18562306a36Sopenharmony_ci else 18662306a36Sopenharmony_ci res = srp_tmo_valid(srp_reconnect_delay, srp_fast_io_fail_tmo, 18762306a36Sopenharmony_ci tmo); 18862306a36Sopenharmony_ci if (res) 18962306a36Sopenharmony_ci goto out; 19062306a36Sopenharmony_ci *(int *)kp->arg = tmo; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ciout: 19362306a36Sopenharmony_ci return res; 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic const struct kernel_param_ops srp_tmo_ops = { 19762306a36Sopenharmony_ci .get = srp_tmo_get, 19862306a36Sopenharmony_ci .set = srp_tmo_set, 19962306a36Sopenharmony_ci}; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistatic inline struct srp_target_port *host_to_target(struct Scsi_Host *host) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci return (struct srp_target_port *) host->hostdata; 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic const char *srp_target_info(struct Scsi_Host *host) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci return host_to_target(host)->target_name; 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic int srp_target_is_topspin(struct srp_target_port *target) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci static const u8 topspin_oui[3] = { 0x00, 0x05, 0xad }; 21462306a36Sopenharmony_ci static const u8 cisco_oui[3] = { 0x00, 0x1b, 0x0d }; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci return topspin_workarounds && 21762306a36Sopenharmony_ci (!memcmp(&target->ioc_guid, topspin_oui, sizeof topspin_oui) || 21862306a36Sopenharmony_ci !memcmp(&target->ioc_guid, cisco_oui, sizeof cisco_oui)); 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic struct srp_iu *srp_alloc_iu(struct srp_host *host, size_t size, 22262306a36Sopenharmony_ci gfp_t gfp_mask, 22362306a36Sopenharmony_ci enum dma_data_direction direction) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci struct srp_iu *iu; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci iu = kmalloc(sizeof *iu, gfp_mask); 22862306a36Sopenharmony_ci if (!iu) 22962306a36Sopenharmony_ci goto out; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci iu->buf = kzalloc(size, gfp_mask); 23262306a36Sopenharmony_ci if (!iu->buf) 23362306a36Sopenharmony_ci goto out_free_iu; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci iu->dma = ib_dma_map_single(host->srp_dev->dev, iu->buf, size, 23662306a36Sopenharmony_ci direction); 23762306a36Sopenharmony_ci if (ib_dma_mapping_error(host->srp_dev->dev, iu->dma)) 23862306a36Sopenharmony_ci goto out_free_buf; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci iu->size = size; 24162306a36Sopenharmony_ci iu->direction = direction; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci return iu; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ciout_free_buf: 24662306a36Sopenharmony_ci kfree(iu->buf); 24762306a36Sopenharmony_ciout_free_iu: 24862306a36Sopenharmony_ci kfree(iu); 24962306a36Sopenharmony_ciout: 25062306a36Sopenharmony_ci return NULL; 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic void srp_free_iu(struct srp_host *host, struct srp_iu *iu) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci if (!iu) 25662306a36Sopenharmony_ci return; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci ib_dma_unmap_single(host->srp_dev->dev, iu->dma, iu->size, 25962306a36Sopenharmony_ci iu->direction); 26062306a36Sopenharmony_ci kfree(iu->buf); 26162306a36Sopenharmony_ci kfree(iu); 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_cistatic void srp_qp_event(struct ib_event *event, void *context) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci pr_debug("QP event %s (%d)\n", 26762306a36Sopenharmony_ci ib_event_msg(event->event), event->event); 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_cistatic int srp_init_ib_qp(struct srp_target_port *target, 27162306a36Sopenharmony_ci struct ib_qp *qp) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci struct ib_qp_attr *attr; 27462306a36Sopenharmony_ci int ret; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci attr = kmalloc(sizeof *attr, GFP_KERNEL); 27762306a36Sopenharmony_ci if (!attr) 27862306a36Sopenharmony_ci return -ENOMEM; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci ret = ib_find_cached_pkey(target->srp_host->srp_dev->dev, 28162306a36Sopenharmony_ci target->srp_host->port, 28262306a36Sopenharmony_ci be16_to_cpu(target->ib_cm.pkey), 28362306a36Sopenharmony_ci &attr->pkey_index); 28462306a36Sopenharmony_ci if (ret) 28562306a36Sopenharmony_ci goto out; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci attr->qp_state = IB_QPS_INIT; 28862306a36Sopenharmony_ci attr->qp_access_flags = (IB_ACCESS_REMOTE_READ | 28962306a36Sopenharmony_ci IB_ACCESS_REMOTE_WRITE); 29062306a36Sopenharmony_ci attr->port_num = target->srp_host->port; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci ret = ib_modify_qp(qp, attr, 29362306a36Sopenharmony_ci IB_QP_STATE | 29462306a36Sopenharmony_ci IB_QP_PKEY_INDEX | 29562306a36Sopenharmony_ci IB_QP_ACCESS_FLAGS | 29662306a36Sopenharmony_ci IB_QP_PORT); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ciout: 29962306a36Sopenharmony_ci kfree(attr); 30062306a36Sopenharmony_ci return ret; 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_cistatic int srp_new_ib_cm_id(struct srp_rdma_ch *ch) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci struct srp_target_port *target = ch->target; 30662306a36Sopenharmony_ci struct ib_cm_id *new_cm_id; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci new_cm_id = ib_create_cm_id(target->srp_host->srp_dev->dev, 30962306a36Sopenharmony_ci srp_ib_cm_handler, ch); 31062306a36Sopenharmony_ci if (IS_ERR(new_cm_id)) 31162306a36Sopenharmony_ci return PTR_ERR(new_cm_id); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci if (ch->ib_cm.cm_id) 31462306a36Sopenharmony_ci ib_destroy_cm_id(ch->ib_cm.cm_id); 31562306a36Sopenharmony_ci ch->ib_cm.cm_id = new_cm_id; 31662306a36Sopenharmony_ci if (rdma_cap_opa_ah(target->srp_host->srp_dev->dev, 31762306a36Sopenharmony_ci target->srp_host->port)) 31862306a36Sopenharmony_ci ch->ib_cm.path.rec_type = SA_PATH_REC_TYPE_OPA; 31962306a36Sopenharmony_ci else 32062306a36Sopenharmony_ci ch->ib_cm.path.rec_type = SA_PATH_REC_TYPE_IB; 32162306a36Sopenharmony_ci ch->ib_cm.path.sgid = target->sgid; 32262306a36Sopenharmony_ci ch->ib_cm.path.dgid = target->ib_cm.orig_dgid; 32362306a36Sopenharmony_ci ch->ib_cm.path.pkey = target->ib_cm.pkey; 32462306a36Sopenharmony_ci ch->ib_cm.path.service_id = target->ib_cm.service_id; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci return 0; 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cistatic int srp_new_rdma_cm_id(struct srp_rdma_ch *ch) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci struct srp_target_port *target = ch->target; 33262306a36Sopenharmony_ci struct rdma_cm_id *new_cm_id; 33362306a36Sopenharmony_ci int ret; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci new_cm_id = rdma_create_id(target->net, srp_rdma_cm_handler, ch, 33662306a36Sopenharmony_ci RDMA_PS_TCP, IB_QPT_RC); 33762306a36Sopenharmony_ci if (IS_ERR(new_cm_id)) { 33862306a36Sopenharmony_ci ret = PTR_ERR(new_cm_id); 33962306a36Sopenharmony_ci new_cm_id = NULL; 34062306a36Sopenharmony_ci goto out; 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci init_completion(&ch->done); 34462306a36Sopenharmony_ci ret = rdma_resolve_addr(new_cm_id, target->rdma_cm.src_specified ? 34562306a36Sopenharmony_ci &target->rdma_cm.src.sa : NULL, 34662306a36Sopenharmony_ci &target->rdma_cm.dst.sa, 34762306a36Sopenharmony_ci SRP_PATH_REC_TIMEOUT_MS); 34862306a36Sopenharmony_ci if (ret) { 34962306a36Sopenharmony_ci pr_err("No route available from %pISpsc to %pISpsc (%d)\n", 35062306a36Sopenharmony_ci &target->rdma_cm.src, &target->rdma_cm.dst, ret); 35162306a36Sopenharmony_ci goto out; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci ret = wait_for_completion_interruptible(&ch->done); 35462306a36Sopenharmony_ci if (ret < 0) 35562306a36Sopenharmony_ci goto out; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci ret = ch->status; 35862306a36Sopenharmony_ci if (ret) { 35962306a36Sopenharmony_ci pr_err("Resolving address %pISpsc failed (%d)\n", 36062306a36Sopenharmony_ci &target->rdma_cm.dst, ret); 36162306a36Sopenharmony_ci goto out; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci swap(ch->rdma_cm.cm_id, new_cm_id); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ciout: 36762306a36Sopenharmony_ci if (new_cm_id) 36862306a36Sopenharmony_ci rdma_destroy_id(new_cm_id); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci return ret; 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_cistatic int srp_new_cm_id(struct srp_rdma_ch *ch) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci struct srp_target_port *target = ch->target; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci return target->using_rdma_cm ? srp_new_rdma_cm_id(ch) : 37862306a36Sopenharmony_ci srp_new_ib_cm_id(ch); 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci/** 38262306a36Sopenharmony_ci * srp_destroy_fr_pool() - free the resources owned by a pool 38362306a36Sopenharmony_ci * @pool: Fast registration pool to be destroyed. 38462306a36Sopenharmony_ci */ 38562306a36Sopenharmony_cistatic void srp_destroy_fr_pool(struct srp_fr_pool *pool) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci int i; 38862306a36Sopenharmony_ci struct srp_fr_desc *d; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci if (!pool) 39162306a36Sopenharmony_ci return; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci for (i = 0, d = &pool->desc[0]; i < pool->size; i++, d++) { 39462306a36Sopenharmony_ci if (d->mr) 39562306a36Sopenharmony_ci ib_dereg_mr(d->mr); 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci kfree(pool); 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci/** 40162306a36Sopenharmony_ci * srp_create_fr_pool() - allocate and initialize a pool for fast registration 40262306a36Sopenharmony_ci * @device: IB device to allocate fast registration descriptors for. 40362306a36Sopenharmony_ci * @pd: Protection domain associated with the FR descriptors. 40462306a36Sopenharmony_ci * @pool_size: Number of descriptors to allocate. 40562306a36Sopenharmony_ci * @max_page_list_len: Maximum fast registration work request page list length. 40662306a36Sopenharmony_ci */ 40762306a36Sopenharmony_cistatic struct srp_fr_pool *srp_create_fr_pool(struct ib_device *device, 40862306a36Sopenharmony_ci struct ib_pd *pd, int pool_size, 40962306a36Sopenharmony_ci int max_page_list_len) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci struct srp_fr_pool *pool; 41262306a36Sopenharmony_ci struct srp_fr_desc *d; 41362306a36Sopenharmony_ci struct ib_mr *mr; 41462306a36Sopenharmony_ci int i, ret = -EINVAL; 41562306a36Sopenharmony_ci enum ib_mr_type mr_type; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci if (pool_size <= 0) 41862306a36Sopenharmony_ci goto err; 41962306a36Sopenharmony_ci ret = -ENOMEM; 42062306a36Sopenharmony_ci pool = kzalloc(struct_size(pool, desc, pool_size), GFP_KERNEL); 42162306a36Sopenharmony_ci if (!pool) 42262306a36Sopenharmony_ci goto err; 42362306a36Sopenharmony_ci pool->size = pool_size; 42462306a36Sopenharmony_ci pool->max_page_list_len = max_page_list_len; 42562306a36Sopenharmony_ci spin_lock_init(&pool->lock); 42662306a36Sopenharmony_ci INIT_LIST_HEAD(&pool->free_list); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci if (device->attrs.kernel_cap_flags & IBK_SG_GAPS_REG) 42962306a36Sopenharmony_ci mr_type = IB_MR_TYPE_SG_GAPS; 43062306a36Sopenharmony_ci else 43162306a36Sopenharmony_ci mr_type = IB_MR_TYPE_MEM_REG; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci for (i = 0, d = &pool->desc[0]; i < pool->size; i++, d++) { 43462306a36Sopenharmony_ci mr = ib_alloc_mr(pd, mr_type, max_page_list_len); 43562306a36Sopenharmony_ci if (IS_ERR(mr)) { 43662306a36Sopenharmony_ci ret = PTR_ERR(mr); 43762306a36Sopenharmony_ci if (ret == -ENOMEM) 43862306a36Sopenharmony_ci pr_info("%s: ib_alloc_mr() failed. Try to reduce max_cmd_per_lun, max_sect or ch_count\n", 43962306a36Sopenharmony_ci dev_name(&device->dev)); 44062306a36Sopenharmony_ci goto destroy_pool; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci d->mr = mr; 44362306a36Sopenharmony_ci list_add_tail(&d->entry, &pool->free_list); 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ciout: 44762306a36Sopenharmony_ci return pool; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cidestroy_pool: 45062306a36Sopenharmony_ci srp_destroy_fr_pool(pool); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_cierr: 45362306a36Sopenharmony_ci pool = ERR_PTR(ret); 45462306a36Sopenharmony_ci goto out; 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci/** 45862306a36Sopenharmony_ci * srp_fr_pool_get() - obtain a descriptor suitable for fast registration 45962306a36Sopenharmony_ci * @pool: Pool to obtain descriptor from. 46062306a36Sopenharmony_ci */ 46162306a36Sopenharmony_cistatic struct srp_fr_desc *srp_fr_pool_get(struct srp_fr_pool *pool) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci struct srp_fr_desc *d = NULL; 46462306a36Sopenharmony_ci unsigned long flags; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci spin_lock_irqsave(&pool->lock, flags); 46762306a36Sopenharmony_ci if (!list_empty(&pool->free_list)) { 46862306a36Sopenharmony_ci d = list_first_entry(&pool->free_list, typeof(*d), entry); 46962306a36Sopenharmony_ci list_del(&d->entry); 47062306a36Sopenharmony_ci } 47162306a36Sopenharmony_ci spin_unlock_irqrestore(&pool->lock, flags); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci return d; 47462306a36Sopenharmony_ci} 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci/** 47762306a36Sopenharmony_ci * srp_fr_pool_put() - put an FR descriptor back in the free list 47862306a36Sopenharmony_ci * @pool: Pool the descriptor was allocated from. 47962306a36Sopenharmony_ci * @desc: Pointer to an array of fast registration descriptor pointers. 48062306a36Sopenharmony_ci * @n: Number of descriptors to put back. 48162306a36Sopenharmony_ci * 48262306a36Sopenharmony_ci * Note: The caller must already have queued an invalidation request for 48362306a36Sopenharmony_ci * desc->mr->rkey before calling this function. 48462306a36Sopenharmony_ci */ 48562306a36Sopenharmony_cistatic void srp_fr_pool_put(struct srp_fr_pool *pool, struct srp_fr_desc **desc, 48662306a36Sopenharmony_ci int n) 48762306a36Sopenharmony_ci{ 48862306a36Sopenharmony_ci unsigned long flags; 48962306a36Sopenharmony_ci int i; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci spin_lock_irqsave(&pool->lock, flags); 49262306a36Sopenharmony_ci for (i = 0; i < n; i++) 49362306a36Sopenharmony_ci list_add(&desc[i]->entry, &pool->free_list); 49462306a36Sopenharmony_ci spin_unlock_irqrestore(&pool->lock, flags); 49562306a36Sopenharmony_ci} 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_cistatic struct srp_fr_pool *srp_alloc_fr_pool(struct srp_target_port *target) 49862306a36Sopenharmony_ci{ 49962306a36Sopenharmony_ci struct srp_device *dev = target->srp_host->srp_dev; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci return srp_create_fr_pool(dev->dev, dev->pd, target->mr_pool_size, 50262306a36Sopenharmony_ci dev->max_pages_per_mr); 50362306a36Sopenharmony_ci} 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci/** 50662306a36Sopenharmony_ci * srp_destroy_qp() - destroy an RDMA queue pair 50762306a36Sopenharmony_ci * @ch: SRP RDMA channel. 50862306a36Sopenharmony_ci * 50962306a36Sopenharmony_ci * Drain the qp before destroying it. This avoids that the receive 51062306a36Sopenharmony_ci * completion handler can access the queue pair while it is 51162306a36Sopenharmony_ci * being destroyed. 51262306a36Sopenharmony_ci */ 51362306a36Sopenharmony_cistatic void srp_destroy_qp(struct srp_rdma_ch *ch) 51462306a36Sopenharmony_ci{ 51562306a36Sopenharmony_ci spin_lock_irq(&ch->lock); 51662306a36Sopenharmony_ci ib_process_cq_direct(ch->send_cq, -1); 51762306a36Sopenharmony_ci spin_unlock_irq(&ch->lock); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci ib_drain_qp(ch->qp); 52062306a36Sopenharmony_ci ib_destroy_qp(ch->qp); 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cistatic int srp_create_ch_ib(struct srp_rdma_ch *ch) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci struct srp_target_port *target = ch->target; 52662306a36Sopenharmony_ci struct srp_device *dev = target->srp_host->srp_dev; 52762306a36Sopenharmony_ci const struct ib_device_attr *attr = &dev->dev->attrs; 52862306a36Sopenharmony_ci struct ib_qp_init_attr *init_attr; 52962306a36Sopenharmony_ci struct ib_cq *recv_cq, *send_cq; 53062306a36Sopenharmony_ci struct ib_qp *qp; 53162306a36Sopenharmony_ci struct srp_fr_pool *fr_pool = NULL; 53262306a36Sopenharmony_ci const int m = 1 + dev->use_fast_reg * target->mr_per_cmd * 2; 53362306a36Sopenharmony_ci int ret; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci init_attr = kzalloc(sizeof *init_attr, GFP_KERNEL); 53662306a36Sopenharmony_ci if (!init_attr) 53762306a36Sopenharmony_ci return -ENOMEM; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci /* queue_size + 1 for ib_drain_rq() */ 54062306a36Sopenharmony_ci recv_cq = ib_alloc_cq(dev->dev, ch, target->queue_size + 1, 54162306a36Sopenharmony_ci ch->comp_vector, IB_POLL_SOFTIRQ); 54262306a36Sopenharmony_ci if (IS_ERR(recv_cq)) { 54362306a36Sopenharmony_ci ret = PTR_ERR(recv_cq); 54462306a36Sopenharmony_ci goto err; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci send_cq = ib_alloc_cq(dev->dev, ch, m * target->queue_size, 54862306a36Sopenharmony_ci ch->comp_vector, IB_POLL_DIRECT); 54962306a36Sopenharmony_ci if (IS_ERR(send_cq)) { 55062306a36Sopenharmony_ci ret = PTR_ERR(send_cq); 55162306a36Sopenharmony_ci goto err_recv_cq; 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci init_attr->event_handler = srp_qp_event; 55562306a36Sopenharmony_ci init_attr->cap.max_send_wr = m * target->queue_size; 55662306a36Sopenharmony_ci init_attr->cap.max_recv_wr = target->queue_size + 1; 55762306a36Sopenharmony_ci init_attr->cap.max_recv_sge = 1; 55862306a36Sopenharmony_ci init_attr->cap.max_send_sge = min(SRP_MAX_SGE, attr->max_send_sge); 55962306a36Sopenharmony_ci init_attr->sq_sig_type = IB_SIGNAL_REQ_WR; 56062306a36Sopenharmony_ci init_attr->qp_type = IB_QPT_RC; 56162306a36Sopenharmony_ci init_attr->send_cq = send_cq; 56262306a36Sopenharmony_ci init_attr->recv_cq = recv_cq; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci ch->max_imm_sge = min(init_attr->cap.max_send_sge - 1U, 255U); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci if (target->using_rdma_cm) { 56762306a36Sopenharmony_ci ret = rdma_create_qp(ch->rdma_cm.cm_id, dev->pd, init_attr); 56862306a36Sopenharmony_ci qp = ch->rdma_cm.cm_id->qp; 56962306a36Sopenharmony_ci } else { 57062306a36Sopenharmony_ci qp = ib_create_qp(dev->pd, init_attr); 57162306a36Sopenharmony_ci if (!IS_ERR(qp)) { 57262306a36Sopenharmony_ci ret = srp_init_ib_qp(target, qp); 57362306a36Sopenharmony_ci if (ret) 57462306a36Sopenharmony_ci ib_destroy_qp(qp); 57562306a36Sopenharmony_ci } else { 57662306a36Sopenharmony_ci ret = PTR_ERR(qp); 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci if (ret) { 58062306a36Sopenharmony_ci pr_err("QP creation failed for dev %s: %d\n", 58162306a36Sopenharmony_ci dev_name(&dev->dev->dev), ret); 58262306a36Sopenharmony_ci goto err_send_cq; 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci if (dev->use_fast_reg) { 58662306a36Sopenharmony_ci fr_pool = srp_alloc_fr_pool(target); 58762306a36Sopenharmony_ci if (IS_ERR(fr_pool)) { 58862306a36Sopenharmony_ci ret = PTR_ERR(fr_pool); 58962306a36Sopenharmony_ci shost_printk(KERN_WARNING, target->scsi_host, PFX 59062306a36Sopenharmony_ci "FR pool allocation failed (%d)\n", ret); 59162306a36Sopenharmony_ci goto err_qp; 59262306a36Sopenharmony_ci } 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci if (ch->qp) 59662306a36Sopenharmony_ci srp_destroy_qp(ch); 59762306a36Sopenharmony_ci if (ch->recv_cq) 59862306a36Sopenharmony_ci ib_free_cq(ch->recv_cq); 59962306a36Sopenharmony_ci if (ch->send_cq) 60062306a36Sopenharmony_ci ib_free_cq(ch->send_cq); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci ch->qp = qp; 60362306a36Sopenharmony_ci ch->recv_cq = recv_cq; 60462306a36Sopenharmony_ci ch->send_cq = send_cq; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci if (dev->use_fast_reg) { 60762306a36Sopenharmony_ci if (ch->fr_pool) 60862306a36Sopenharmony_ci srp_destroy_fr_pool(ch->fr_pool); 60962306a36Sopenharmony_ci ch->fr_pool = fr_pool; 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci kfree(init_attr); 61362306a36Sopenharmony_ci return 0; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_cierr_qp: 61662306a36Sopenharmony_ci if (target->using_rdma_cm) 61762306a36Sopenharmony_ci rdma_destroy_qp(ch->rdma_cm.cm_id); 61862306a36Sopenharmony_ci else 61962306a36Sopenharmony_ci ib_destroy_qp(qp); 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_cierr_send_cq: 62262306a36Sopenharmony_ci ib_free_cq(send_cq); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_cierr_recv_cq: 62562306a36Sopenharmony_ci ib_free_cq(recv_cq); 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_cierr: 62862306a36Sopenharmony_ci kfree(init_attr); 62962306a36Sopenharmony_ci return ret; 63062306a36Sopenharmony_ci} 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci/* 63362306a36Sopenharmony_ci * Note: this function may be called without srp_alloc_iu_bufs() having been 63462306a36Sopenharmony_ci * invoked. Hence the ch->[rt]x_ring checks. 63562306a36Sopenharmony_ci */ 63662306a36Sopenharmony_cistatic void srp_free_ch_ib(struct srp_target_port *target, 63762306a36Sopenharmony_ci struct srp_rdma_ch *ch) 63862306a36Sopenharmony_ci{ 63962306a36Sopenharmony_ci struct srp_device *dev = target->srp_host->srp_dev; 64062306a36Sopenharmony_ci int i; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci if (!ch->target) 64362306a36Sopenharmony_ci return; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci if (target->using_rdma_cm) { 64662306a36Sopenharmony_ci if (ch->rdma_cm.cm_id) { 64762306a36Sopenharmony_ci rdma_destroy_id(ch->rdma_cm.cm_id); 64862306a36Sopenharmony_ci ch->rdma_cm.cm_id = NULL; 64962306a36Sopenharmony_ci } 65062306a36Sopenharmony_ci } else { 65162306a36Sopenharmony_ci if (ch->ib_cm.cm_id) { 65262306a36Sopenharmony_ci ib_destroy_cm_id(ch->ib_cm.cm_id); 65362306a36Sopenharmony_ci ch->ib_cm.cm_id = NULL; 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_ci } 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci /* If srp_new_cm_id() succeeded but srp_create_ch_ib() not, return. */ 65862306a36Sopenharmony_ci if (!ch->qp) 65962306a36Sopenharmony_ci return; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci if (dev->use_fast_reg) { 66262306a36Sopenharmony_ci if (ch->fr_pool) 66362306a36Sopenharmony_ci srp_destroy_fr_pool(ch->fr_pool); 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci srp_destroy_qp(ch); 66762306a36Sopenharmony_ci ib_free_cq(ch->send_cq); 66862306a36Sopenharmony_ci ib_free_cq(ch->recv_cq); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci /* 67162306a36Sopenharmony_ci * Avoid that the SCSI error handler tries to use this channel after 67262306a36Sopenharmony_ci * it has been freed. The SCSI error handler can namely continue 67362306a36Sopenharmony_ci * trying to perform recovery actions after scsi_remove_host() 67462306a36Sopenharmony_ci * returned. 67562306a36Sopenharmony_ci */ 67662306a36Sopenharmony_ci ch->target = NULL; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci ch->qp = NULL; 67962306a36Sopenharmony_ci ch->send_cq = ch->recv_cq = NULL; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci if (ch->rx_ring) { 68262306a36Sopenharmony_ci for (i = 0; i < target->queue_size; ++i) 68362306a36Sopenharmony_ci srp_free_iu(target->srp_host, ch->rx_ring[i]); 68462306a36Sopenharmony_ci kfree(ch->rx_ring); 68562306a36Sopenharmony_ci ch->rx_ring = NULL; 68662306a36Sopenharmony_ci } 68762306a36Sopenharmony_ci if (ch->tx_ring) { 68862306a36Sopenharmony_ci for (i = 0; i < target->queue_size; ++i) 68962306a36Sopenharmony_ci srp_free_iu(target->srp_host, ch->tx_ring[i]); 69062306a36Sopenharmony_ci kfree(ch->tx_ring); 69162306a36Sopenharmony_ci ch->tx_ring = NULL; 69262306a36Sopenharmony_ci } 69362306a36Sopenharmony_ci} 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_cistatic void srp_path_rec_completion(int status, 69662306a36Sopenharmony_ci struct sa_path_rec *pathrec, 69762306a36Sopenharmony_ci unsigned int num_paths, void *ch_ptr) 69862306a36Sopenharmony_ci{ 69962306a36Sopenharmony_ci struct srp_rdma_ch *ch = ch_ptr; 70062306a36Sopenharmony_ci struct srp_target_port *target = ch->target; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci ch->status = status; 70362306a36Sopenharmony_ci if (status) 70462306a36Sopenharmony_ci shost_printk(KERN_ERR, target->scsi_host, 70562306a36Sopenharmony_ci PFX "Got failed path rec status %d\n", status); 70662306a36Sopenharmony_ci else 70762306a36Sopenharmony_ci ch->ib_cm.path = *pathrec; 70862306a36Sopenharmony_ci complete(&ch->done); 70962306a36Sopenharmony_ci} 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_cistatic int srp_ib_lookup_path(struct srp_rdma_ch *ch) 71262306a36Sopenharmony_ci{ 71362306a36Sopenharmony_ci struct srp_target_port *target = ch->target; 71462306a36Sopenharmony_ci int ret; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci ch->ib_cm.path.numb_path = 1; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci init_completion(&ch->done); 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci ch->ib_cm.path_query_id = ib_sa_path_rec_get(&srp_sa_client, 72162306a36Sopenharmony_ci target->srp_host->srp_dev->dev, 72262306a36Sopenharmony_ci target->srp_host->port, 72362306a36Sopenharmony_ci &ch->ib_cm.path, 72462306a36Sopenharmony_ci IB_SA_PATH_REC_SERVICE_ID | 72562306a36Sopenharmony_ci IB_SA_PATH_REC_DGID | 72662306a36Sopenharmony_ci IB_SA_PATH_REC_SGID | 72762306a36Sopenharmony_ci IB_SA_PATH_REC_NUMB_PATH | 72862306a36Sopenharmony_ci IB_SA_PATH_REC_PKEY, 72962306a36Sopenharmony_ci SRP_PATH_REC_TIMEOUT_MS, 73062306a36Sopenharmony_ci GFP_KERNEL, 73162306a36Sopenharmony_ci srp_path_rec_completion, 73262306a36Sopenharmony_ci ch, &ch->ib_cm.path_query); 73362306a36Sopenharmony_ci if (ch->ib_cm.path_query_id < 0) 73462306a36Sopenharmony_ci return ch->ib_cm.path_query_id; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci ret = wait_for_completion_interruptible(&ch->done); 73762306a36Sopenharmony_ci if (ret < 0) 73862306a36Sopenharmony_ci return ret; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci if (ch->status < 0) 74162306a36Sopenharmony_ci shost_printk(KERN_WARNING, target->scsi_host, 74262306a36Sopenharmony_ci PFX "Path record query failed: sgid %pI6, dgid %pI6, pkey %#04x, service_id %#16llx\n", 74362306a36Sopenharmony_ci ch->ib_cm.path.sgid.raw, ch->ib_cm.path.dgid.raw, 74462306a36Sopenharmony_ci be16_to_cpu(target->ib_cm.pkey), 74562306a36Sopenharmony_ci be64_to_cpu(target->ib_cm.service_id)); 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci return ch->status; 74862306a36Sopenharmony_ci} 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_cistatic int srp_rdma_lookup_path(struct srp_rdma_ch *ch) 75162306a36Sopenharmony_ci{ 75262306a36Sopenharmony_ci struct srp_target_port *target = ch->target; 75362306a36Sopenharmony_ci int ret; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci init_completion(&ch->done); 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci ret = rdma_resolve_route(ch->rdma_cm.cm_id, SRP_PATH_REC_TIMEOUT_MS); 75862306a36Sopenharmony_ci if (ret) 75962306a36Sopenharmony_ci return ret; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci wait_for_completion_interruptible(&ch->done); 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci if (ch->status != 0) 76462306a36Sopenharmony_ci shost_printk(KERN_WARNING, target->scsi_host, 76562306a36Sopenharmony_ci PFX "Path resolution failed\n"); 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci return ch->status; 76862306a36Sopenharmony_ci} 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_cistatic int srp_lookup_path(struct srp_rdma_ch *ch) 77162306a36Sopenharmony_ci{ 77262306a36Sopenharmony_ci struct srp_target_port *target = ch->target; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci return target->using_rdma_cm ? srp_rdma_lookup_path(ch) : 77562306a36Sopenharmony_ci srp_ib_lookup_path(ch); 77662306a36Sopenharmony_ci} 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_cistatic u8 srp_get_subnet_timeout(struct srp_host *host) 77962306a36Sopenharmony_ci{ 78062306a36Sopenharmony_ci struct ib_port_attr attr; 78162306a36Sopenharmony_ci int ret; 78262306a36Sopenharmony_ci u8 subnet_timeout = 18; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci ret = ib_query_port(host->srp_dev->dev, host->port, &attr); 78562306a36Sopenharmony_ci if (ret == 0) 78662306a36Sopenharmony_ci subnet_timeout = attr.subnet_timeout; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci if (unlikely(subnet_timeout < 15)) 78962306a36Sopenharmony_ci pr_warn("%s: subnet timeout %d may cause SRP login to fail.\n", 79062306a36Sopenharmony_ci dev_name(&host->srp_dev->dev->dev), subnet_timeout); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci return subnet_timeout; 79362306a36Sopenharmony_ci} 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_cistatic int srp_send_req(struct srp_rdma_ch *ch, uint32_t max_iu_len, 79662306a36Sopenharmony_ci bool multich) 79762306a36Sopenharmony_ci{ 79862306a36Sopenharmony_ci struct srp_target_port *target = ch->target; 79962306a36Sopenharmony_ci struct { 80062306a36Sopenharmony_ci struct rdma_conn_param rdma_param; 80162306a36Sopenharmony_ci struct srp_login_req_rdma rdma_req; 80262306a36Sopenharmony_ci struct ib_cm_req_param ib_param; 80362306a36Sopenharmony_ci struct srp_login_req ib_req; 80462306a36Sopenharmony_ci } *req = NULL; 80562306a36Sopenharmony_ci char *ipi, *tpi; 80662306a36Sopenharmony_ci int status; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci req = kzalloc(sizeof *req, GFP_KERNEL); 80962306a36Sopenharmony_ci if (!req) 81062306a36Sopenharmony_ci return -ENOMEM; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci req->ib_param.flow_control = 1; 81362306a36Sopenharmony_ci req->ib_param.retry_count = target->tl_retry_count; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci /* 81662306a36Sopenharmony_ci * Pick some arbitrary defaults here; we could make these 81762306a36Sopenharmony_ci * module parameters if anyone cared about setting them. 81862306a36Sopenharmony_ci */ 81962306a36Sopenharmony_ci req->ib_param.responder_resources = 4; 82062306a36Sopenharmony_ci req->ib_param.rnr_retry_count = 7; 82162306a36Sopenharmony_ci req->ib_param.max_cm_retries = 15; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci req->ib_req.opcode = SRP_LOGIN_REQ; 82462306a36Sopenharmony_ci req->ib_req.tag = 0; 82562306a36Sopenharmony_ci req->ib_req.req_it_iu_len = cpu_to_be32(max_iu_len); 82662306a36Sopenharmony_ci req->ib_req.req_buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT | 82762306a36Sopenharmony_ci SRP_BUF_FORMAT_INDIRECT); 82862306a36Sopenharmony_ci req->ib_req.req_flags = (multich ? SRP_MULTICHAN_MULTI : 82962306a36Sopenharmony_ci SRP_MULTICHAN_SINGLE); 83062306a36Sopenharmony_ci if (srp_use_imm_data) { 83162306a36Sopenharmony_ci req->ib_req.req_flags |= SRP_IMMED_REQUESTED; 83262306a36Sopenharmony_ci req->ib_req.imm_data_offset = cpu_to_be16(SRP_IMM_DATA_OFFSET); 83362306a36Sopenharmony_ci } 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci if (target->using_rdma_cm) { 83662306a36Sopenharmony_ci req->rdma_param.flow_control = req->ib_param.flow_control; 83762306a36Sopenharmony_ci req->rdma_param.responder_resources = 83862306a36Sopenharmony_ci req->ib_param.responder_resources; 83962306a36Sopenharmony_ci req->rdma_param.initiator_depth = req->ib_param.initiator_depth; 84062306a36Sopenharmony_ci req->rdma_param.retry_count = req->ib_param.retry_count; 84162306a36Sopenharmony_ci req->rdma_param.rnr_retry_count = req->ib_param.rnr_retry_count; 84262306a36Sopenharmony_ci req->rdma_param.private_data = &req->rdma_req; 84362306a36Sopenharmony_ci req->rdma_param.private_data_len = sizeof(req->rdma_req); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci req->rdma_req.opcode = req->ib_req.opcode; 84662306a36Sopenharmony_ci req->rdma_req.tag = req->ib_req.tag; 84762306a36Sopenharmony_ci req->rdma_req.req_it_iu_len = req->ib_req.req_it_iu_len; 84862306a36Sopenharmony_ci req->rdma_req.req_buf_fmt = req->ib_req.req_buf_fmt; 84962306a36Sopenharmony_ci req->rdma_req.req_flags = req->ib_req.req_flags; 85062306a36Sopenharmony_ci req->rdma_req.imm_data_offset = req->ib_req.imm_data_offset; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci ipi = req->rdma_req.initiator_port_id; 85362306a36Sopenharmony_ci tpi = req->rdma_req.target_port_id; 85462306a36Sopenharmony_ci } else { 85562306a36Sopenharmony_ci u8 subnet_timeout; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci subnet_timeout = srp_get_subnet_timeout(target->srp_host); 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci req->ib_param.primary_path = &ch->ib_cm.path; 86062306a36Sopenharmony_ci req->ib_param.alternate_path = NULL; 86162306a36Sopenharmony_ci req->ib_param.service_id = target->ib_cm.service_id; 86262306a36Sopenharmony_ci get_random_bytes(&req->ib_param.starting_psn, 4); 86362306a36Sopenharmony_ci req->ib_param.starting_psn &= 0xffffff; 86462306a36Sopenharmony_ci req->ib_param.qp_num = ch->qp->qp_num; 86562306a36Sopenharmony_ci req->ib_param.qp_type = ch->qp->qp_type; 86662306a36Sopenharmony_ci req->ib_param.local_cm_response_timeout = subnet_timeout + 2; 86762306a36Sopenharmony_ci req->ib_param.remote_cm_response_timeout = subnet_timeout + 2; 86862306a36Sopenharmony_ci req->ib_param.private_data = &req->ib_req; 86962306a36Sopenharmony_ci req->ib_param.private_data_len = sizeof(req->ib_req); 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci ipi = req->ib_req.initiator_port_id; 87262306a36Sopenharmony_ci tpi = req->ib_req.target_port_id; 87362306a36Sopenharmony_ci } 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci /* 87662306a36Sopenharmony_ci * In the published SRP specification (draft rev. 16a), the 87762306a36Sopenharmony_ci * port identifier format is 8 bytes of ID extension followed 87862306a36Sopenharmony_ci * by 8 bytes of GUID. Older drafts put the two halves in the 87962306a36Sopenharmony_ci * opposite order, so that the GUID comes first. 88062306a36Sopenharmony_ci * 88162306a36Sopenharmony_ci * Targets conforming to these obsolete drafts can be 88262306a36Sopenharmony_ci * recognized by the I/O Class they report. 88362306a36Sopenharmony_ci */ 88462306a36Sopenharmony_ci if (target->io_class == SRP_REV10_IB_IO_CLASS) { 88562306a36Sopenharmony_ci memcpy(ipi, &target->sgid.global.interface_id, 8); 88662306a36Sopenharmony_ci memcpy(ipi + 8, &target->initiator_ext, 8); 88762306a36Sopenharmony_ci memcpy(tpi, &target->ioc_guid, 8); 88862306a36Sopenharmony_ci memcpy(tpi + 8, &target->id_ext, 8); 88962306a36Sopenharmony_ci } else { 89062306a36Sopenharmony_ci memcpy(ipi, &target->initiator_ext, 8); 89162306a36Sopenharmony_ci memcpy(ipi + 8, &target->sgid.global.interface_id, 8); 89262306a36Sopenharmony_ci memcpy(tpi, &target->id_ext, 8); 89362306a36Sopenharmony_ci memcpy(tpi + 8, &target->ioc_guid, 8); 89462306a36Sopenharmony_ci } 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci /* 89762306a36Sopenharmony_ci * Topspin/Cisco SRP targets will reject our login unless we 89862306a36Sopenharmony_ci * zero out the first 8 bytes of our initiator port ID and set 89962306a36Sopenharmony_ci * the second 8 bytes to the local node GUID. 90062306a36Sopenharmony_ci */ 90162306a36Sopenharmony_ci if (srp_target_is_topspin(target)) { 90262306a36Sopenharmony_ci shost_printk(KERN_DEBUG, target->scsi_host, 90362306a36Sopenharmony_ci PFX "Topspin/Cisco initiator port ID workaround " 90462306a36Sopenharmony_ci "activated for target GUID %016llx\n", 90562306a36Sopenharmony_ci be64_to_cpu(target->ioc_guid)); 90662306a36Sopenharmony_ci memset(ipi, 0, 8); 90762306a36Sopenharmony_ci memcpy(ipi + 8, &target->srp_host->srp_dev->dev->node_guid, 8); 90862306a36Sopenharmony_ci } 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci if (target->using_rdma_cm) 91162306a36Sopenharmony_ci status = rdma_connect(ch->rdma_cm.cm_id, &req->rdma_param); 91262306a36Sopenharmony_ci else 91362306a36Sopenharmony_ci status = ib_send_cm_req(ch->ib_cm.cm_id, &req->ib_param); 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci kfree(req); 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci return status; 91862306a36Sopenharmony_ci} 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_cistatic bool srp_queue_remove_work(struct srp_target_port *target) 92162306a36Sopenharmony_ci{ 92262306a36Sopenharmony_ci bool changed = false; 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci spin_lock_irq(&target->lock); 92562306a36Sopenharmony_ci if (target->state != SRP_TARGET_REMOVED) { 92662306a36Sopenharmony_ci target->state = SRP_TARGET_REMOVED; 92762306a36Sopenharmony_ci changed = true; 92862306a36Sopenharmony_ci } 92962306a36Sopenharmony_ci spin_unlock_irq(&target->lock); 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci if (changed) 93262306a36Sopenharmony_ci queue_work(srp_remove_wq, &target->remove_work); 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci return changed; 93562306a36Sopenharmony_ci} 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_cistatic void srp_disconnect_target(struct srp_target_port *target) 93862306a36Sopenharmony_ci{ 93962306a36Sopenharmony_ci struct srp_rdma_ch *ch; 94062306a36Sopenharmony_ci int i, ret; 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci /* XXX should send SRP_I_LOGOUT request */ 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci for (i = 0; i < target->ch_count; i++) { 94562306a36Sopenharmony_ci ch = &target->ch[i]; 94662306a36Sopenharmony_ci ch->connected = false; 94762306a36Sopenharmony_ci ret = 0; 94862306a36Sopenharmony_ci if (target->using_rdma_cm) { 94962306a36Sopenharmony_ci if (ch->rdma_cm.cm_id) 95062306a36Sopenharmony_ci rdma_disconnect(ch->rdma_cm.cm_id); 95162306a36Sopenharmony_ci } else { 95262306a36Sopenharmony_ci if (ch->ib_cm.cm_id) 95362306a36Sopenharmony_ci ret = ib_send_cm_dreq(ch->ib_cm.cm_id, 95462306a36Sopenharmony_ci NULL, 0); 95562306a36Sopenharmony_ci } 95662306a36Sopenharmony_ci if (ret < 0) { 95762306a36Sopenharmony_ci shost_printk(KERN_DEBUG, target->scsi_host, 95862306a36Sopenharmony_ci PFX "Sending CM DREQ failed\n"); 95962306a36Sopenharmony_ci } 96062306a36Sopenharmony_ci } 96162306a36Sopenharmony_ci} 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_cistatic int srp_exit_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *cmd) 96462306a36Sopenharmony_ci{ 96562306a36Sopenharmony_ci struct srp_target_port *target = host_to_target(shost); 96662306a36Sopenharmony_ci struct srp_device *dev = target->srp_host->srp_dev; 96762306a36Sopenharmony_ci struct ib_device *ibdev = dev->dev; 96862306a36Sopenharmony_ci struct srp_request *req = scsi_cmd_priv(cmd); 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci kfree(req->fr_list); 97162306a36Sopenharmony_ci if (req->indirect_dma_addr) { 97262306a36Sopenharmony_ci ib_dma_unmap_single(ibdev, req->indirect_dma_addr, 97362306a36Sopenharmony_ci target->indirect_size, 97462306a36Sopenharmony_ci DMA_TO_DEVICE); 97562306a36Sopenharmony_ci } 97662306a36Sopenharmony_ci kfree(req->indirect_desc); 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci return 0; 97962306a36Sopenharmony_ci} 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_cistatic int srp_init_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *cmd) 98262306a36Sopenharmony_ci{ 98362306a36Sopenharmony_ci struct srp_target_port *target = host_to_target(shost); 98462306a36Sopenharmony_ci struct srp_device *srp_dev = target->srp_host->srp_dev; 98562306a36Sopenharmony_ci struct ib_device *ibdev = srp_dev->dev; 98662306a36Sopenharmony_ci struct srp_request *req = scsi_cmd_priv(cmd); 98762306a36Sopenharmony_ci dma_addr_t dma_addr; 98862306a36Sopenharmony_ci int ret = -ENOMEM; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci if (srp_dev->use_fast_reg) { 99162306a36Sopenharmony_ci req->fr_list = kmalloc_array(target->mr_per_cmd, sizeof(void *), 99262306a36Sopenharmony_ci GFP_KERNEL); 99362306a36Sopenharmony_ci if (!req->fr_list) 99462306a36Sopenharmony_ci goto out; 99562306a36Sopenharmony_ci } 99662306a36Sopenharmony_ci req->indirect_desc = kmalloc(target->indirect_size, GFP_KERNEL); 99762306a36Sopenharmony_ci if (!req->indirect_desc) 99862306a36Sopenharmony_ci goto out; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci dma_addr = ib_dma_map_single(ibdev, req->indirect_desc, 100162306a36Sopenharmony_ci target->indirect_size, 100262306a36Sopenharmony_ci DMA_TO_DEVICE); 100362306a36Sopenharmony_ci if (ib_dma_mapping_error(ibdev, dma_addr)) { 100462306a36Sopenharmony_ci srp_exit_cmd_priv(shost, cmd); 100562306a36Sopenharmony_ci goto out; 100662306a36Sopenharmony_ci } 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci req->indirect_dma_addr = dma_addr; 100962306a36Sopenharmony_ci ret = 0; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ciout: 101262306a36Sopenharmony_ci return ret; 101362306a36Sopenharmony_ci} 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci/** 101662306a36Sopenharmony_ci * srp_del_scsi_host_attr() - Remove attributes defined in the host template. 101762306a36Sopenharmony_ci * @shost: SCSI host whose attributes to remove from sysfs. 101862306a36Sopenharmony_ci * 101962306a36Sopenharmony_ci * Note: Any attributes defined in the host template and that did not exist 102062306a36Sopenharmony_ci * before invocation of this function will be ignored. 102162306a36Sopenharmony_ci */ 102262306a36Sopenharmony_cistatic void srp_del_scsi_host_attr(struct Scsi_Host *shost) 102362306a36Sopenharmony_ci{ 102462306a36Sopenharmony_ci const struct attribute_group **g; 102562306a36Sopenharmony_ci struct attribute **attr; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci for (g = shost->hostt->shost_groups; *g; ++g) { 102862306a36Sopenharmony_ci for (attr = (*g)->attrs; *attr; ++attr) { 102962306a36Sopenharmony_ci struct device_attribute *dev_attr = 103062306a36Sopenharmony_ci container_of(*attr, typeof(*dev_attr), attr); 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci device_remove_file(&shost->shost_dev, dev_attr); 103362306a36Sopenharmony_ci } 103462306a36Sopenharmony_ci } 103562306a36Sopenharmony_ci} 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_cistatic void srp_remove_target(struct srp_target_port *target) 103862306a36Sopenharmony_ci{ 103962306a36Sopenharmony_ci struct srp_rdma_ch *ch; 104062306a36Sopenharmony_ci int i; 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci WARN_ON_ONCE(target->state != SRP_TARGET_REMOVED); 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci srp_del_scsi_host_attr(target->scsi_host); 104562306a36Sopenharmony_ci srp_rport_get(target->rport); 104662306a36Sopenharmony_ci srp_remove_host(target->scsi_host); 104762306a36Sopenharmony_ci scsi_remove_host(target->scsi_host); 104862306a36Sopenharmony_ci srp_stop_rport_timers(target->rport); 104962306a36Sopenharmony_ci srp_disconnect_target(target); 105062306a36Sopenharmony_ci kobj_ns_drop(KOBJ_NS_TYPE_NET, target->net); 105162306a36Sopenharmony_ci for (i = 0; i < target->ch_count; i++) { 105262306a36Sopenharmony_ci ch = &target->ch[i]; 105362306a36Sopenharmony_ci srp_free_ch_ib(target, ch); 105462306a36Sopenharmony_ci } 105562306a36Sopenharmony_ci cancel_work_sync(&target->tl_err_work); 105662306a36Sopenharmony_ci srp_rport_put(target->rport); 105762306a36Sopenharmony_ci kfree(target->ch); 105862306a36Sopenharmony_ci target->ch = NULL; 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci spin_lock(&target->srp_host->target_lock); 106162306a36Sopenharmony_ci list_del(&target->list); 106262306a36Sopenharmony_ci spin_unlock(&target->srp_host->target_lock); 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci scsi_host_put(target->scsi_host); 106562306a36Sopenharmony_ci} 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_cistatic void srp_remove_work(struct work_struct *work) 106862306a36Sopenharmony_ci{ 106962306a36Sopenharmony_ci struct srp_target_port *target = 107062306a36Sopenharmony_ci container_of(work, struct srp_target_port, remove_work); 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci WARN_ON_ONCE(target->state != SRP_TARGET_REMOVED); 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci srp_remove_target(target); 107562306a36Sopenharmony_ci} 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_cistatic void srp_rport_delete(struct srp_rport *rport) 107862306a36Sopenharmony_ci{ 107962306a36Sopenharmony_ci struct srp_target_port *target = rport->lld_data; 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci srp_queue_remove_work(target); 108262306a36Sopenharmony_ci} 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci/** 108562306a36Sopenharmony_ci * srp_connected_ch() - number of connected channels 108662306a36Sopenharmony_ci * @target: SRP target port. 108762306a36Sopenharmony_ci */ 108862306a36Sopenharmony_cistatic int srp_connected_ch(struct srp_target_port *target) 108962306a36Sopenharmony_ci{ 109062306a36Sopenharmony_ci int i, c = 0; 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci for (i = 0; i < target->ch_count; i++) 109362306a36Sopenharmony_ci c += target->ch[i].connected; 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci return c; 109662306a36Sopenharmony_ci} 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_cistatic int srp_connect_ch(struct srp_rdma_ch *ch, uint32_t max_iu_len, 109962306a36Sopenharmony_ci bool multich) 110062306a36Sopenharmony_ci{ 110162306a36Sopenharmony_ci struct srp_target_port *target = ch->target; 110262306a36Sopenharmony_ci int ret; 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci WARN_ON_ONCE(!multich && srp_connected_ch(target) > 0); 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci ret = srp_lookup_path(ch); 110762306a36Sopenharmony_ci if (ret) 110862306a36Sopenharmony_ci goto out; 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci while (1) { 111162306a36Sopenharmony_ci init_completion(&ch->done); 111262306a36Sopenharmony_ci ret = srp_send_req(ch, max_iu_len, multich); 111362306a36Sopenharmony_ci if (ret) 111462306a36Sopenharmony_ci goto out; 111562306a36Sopenharmony_ci ret = wait_for_completion_interruptible(&ch->done); 111662306a36Sopenharmony_ci if (ret < 0) 111762306a36Sopenharmony_ci goto out; 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci /* 112062306a36Sopenharmony_ci * The CM event handling code will set status to 112162306a36Sopenharmony_ci * SRP_PORT_REDIRECT if we get a port redirect REJ 112262306a36Sopenharmony_ci * back, or SRP_DLID_REDIRECT if we get a lid/qp 112362306a36Sopenharmony_ci * redirect REJ back. 112462306a36Sopenharmony_ci */ 112562306a36Sopenharmony_ci ret = ch->status; 112662306a36Sopenharmony_ci switch (ret) { 112762306a36Sopenharmony_ci case 0: 112862306a36Sopenharmony_ci ch->connected = true; 112962306a36Sopenharmony_ci goto out; 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci case SRP_PORT_REDIRECT: 113262306a36Sopenharmony_ci ret = srp_lookup_path(ch); 113362306a36Sopenharmony_ci if (ret) 113462306a36Sopenharmony_ci goto out; 113562306a36Sopenharmony_ci break; 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci case SRP_DLID_REDIRECT: 113862306a36Sopenharmony_ci break; 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci case SRP_STALE_CONN: 114162306a36Sopenharmony_ci shost_printk(KERN_ERR, target->scsi_host, PFX 114262306a36Sopenharmony_ci "giving up on stale connection\n"); 114362306a36Sopenharmony_ci ret = -ECONNRESET; 114462306a36Sopenharmony_ci goto out; 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci default: 114762306a36Sopenharmony_ci goto out; 114862306a36Sopenharmony_ci } 114962306a36Sopenharmony_ci } 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ciout: 115262306a36Sopenharmony_ci return ret <= 0 ? ret : -ENODEV; 115362306a36Sopenharmony_ci} 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_cistatic void srp_inv_rkey_err_done(struct ib_cq *cq, struct ib_wc *wc) 115662306a36Sopenharmony_ci{ 115762306a36Sopenharmony_ci srp_handle_qp_err(cq, wc, "INV RKEY"); 115862306a36Sopenharmony_ci} 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_cistatic int srp_inv_rkey(struct srp_request *req, struct srp_rdma_ch *ch, 116162306a36Sopenharmony_ci u32 rkey) 116262306a36Sopenharmony_ci{ 116362306a36Sopenharmony_ci struct ib_send_wr wr = { 116462306a36Sopenharmony_ci .opcode = IB_WR_LOCAL_INV, 116562306a36Sopenharmony_ci .next = NULL, 116662306a36Sopenharmony_ci .num_sge = 0, 116762306a36Sopenharmony_ci .send_flags = 0, 116862306a36Sopenharmony_ci .ex.invalidate_rkey = rkey, 116962306a36Sopenharmony_ci }; 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci wr.wr_cqe = &req->reg_cqe; 117262306a36Sopenharmony_ci req->reg_cqe.done = srp_inv_rkey_err_done; 117362306a36Sopenharmony_ci return ib_post_send(ch->qp, &wr, NULL); 117462306a36Sopenharmony_ci} 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_cistatic void srp_unmap_data(struct scsi_cmnd *scmnd, 117762306a36Sopenharmony_ci struct srp_rdma_ch *ch, 117862306a36Sopenharmony_ci struct srp_request *req) 117962306a36Sopenharmony_ci{ 118062306a36Sopenharmony_ci struct srp_target_port *target = ch->target; 118162306a36Sopenharmony_ci struct srp_device *dev = target->srp_host->srp_dev; 118262306a36Sopenharmony_ci struct ib_device *ibdev = dev->dev; 118362306a36Sopenharmony_ci int i, res; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci if (!scsi_sglist(scmnd) || 118662306a36Sopenharmony_ci (scmnd->sc_data_direction != DMA_TO_DEVICE && 118762306a36Sopenharmony_ci scmnd->sc_data_direction != DMA_FROM_DEVICE)) 118862306a36Sopenharmony_ci return; 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci if (dev->use_fast_reg) { 119162306a36Sopenharmony_ci struct srp_fr_desc **pfr; 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci for (i = req->nmdesc, pfr = req->fr_list; i > 0; i--, pfr++) { 119462306a36Sopenharmony_ci res = srp_inv_rkey(req, ch, (*pfr)->mr->rkey); 119562306a36Sopenharmony_ci if (res < 0) { 119662306a36Sopenharmony_ci shost_printk(KERN_ERR, target->scsi_host, PFX 119762306a36Sopenharmony_ci "Queueing INV WR for rkey %#x failed (%d)\n", 119862306a36Sopenharmony_ci (*pfr)->mr->rkey, res); 119962306a36Sopenharmony_ci queue_work(system_long_wq, 120062306a36Sopenharmony_ci &target->tl_err_work); 120162306a36Sopenharmony_ci } 120262306a36Sopenharmony_ci } 120362306a36Sopenharmony_ci if (req->nmdesc) 120462306a36Sopenharmony_ci srp_fr_pool_put(ch->fr_pool, req->fr_list, 120562306a36Sopenharmony_ci req->nmdesc); 120662306a36Sopenharmony_ci } 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci ib_dma_unmap_sg(ibdev, scsi_sglist(scmnd), scsi_sg_count(scmnd), 120962306a36Sopenharmony_ci scmnd->sc_data_direction); 121062306a36Sopenharmony_ci} 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci/** 121362306a36Sopenharmony_ci * srp_claim_req - Take ownership of the scmnd associated with a request. 121462306a36Sopenharmony_ci * @ch: SRP RDMA channel. 121562306a36Sopenharmony_ci * @req: SRP request. 121662306a36Sopenharmony_ci * @sdev: If not NULL, only take ownership for this SCSI device. 121762306a36Sopenharmony_ci * @scmnd: If NULL, take ownership of @req->scmnd. If not NULL, only take 121862306a36Sopenharmony_ci * ownership of @req->scmnd if it equals @scmnd. 121962306a36Sopenharmony_ci * 122062306a36Sopenharmony_ci * Return value: 122162306a36Sopenharmony_ci * Either NULL or a pointer to the SCSI command the caller became owner of. 122262306a36Sopenharmony_ci */ 122362306a36Sopenharmony_cistatic struct scsi_cmnd *srp_claim_req(struct srp_rdma_ch *ch, 122462306a36Sopenharmony_ci struct srp_request *req, 122562306a36Sopenharmony_ci struct scsi_device *sdev, 122662306a36Sopenharmony_ci struct scsi_cmnd *scmnd) 122762306a36Sopenharmony_ci{ 122862306a36Sopenharmony_ci unsigned long flags; 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci spin_lock_irqsave(&ch->lock, flags); 123162306a36Sopenharmony_ci if (req->scmnd && 123262306a36Sopenharmony_ci (!sdev || req->scmnd->device == sdev) && 123362306a36Sopenharmony_ci (!scmnd || req->scmnd == scmnd)) { 123462306a36Sopenharmony_ci scmnd = req->scmnd; 123562306a36Sopenharmony_ci req->scmnd = NULL; 123662306a36Sopenharmony_ci } else { 123762306a36Sopenharmony_ci scmnd = NULL; 123862306a36Sopenharmony_ci } 123962306a36Sopenharmony_ci spin_unlock_irqrestore(&ch->lock, flags); 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci return scmnd; 124262306a36Sopenharmony_ci} 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci/** 124562306a36Sopenharmony_ci * srp_free_req() - Unmap data and adjust ch->req_lim. 124662306a36Sopenharmony_ci * @ch: SRP RDMA channel. 124762306a36Sopenharmony_ci * @req: Request to be freed. 124862306a36Sopenharmony_ci * @scmnd: SCSI command associated with @req. 124962306a36Sopenharmony_ci * @req_lim_delta: Amount to be added to @target->req_lim. 125062306a36Sopenharmony_ci */ 125162306a36Sopenharmony_cistatic void srp_free_req(struct srp_rdma_ch *ch, struct srp_request *req, 125262306a36Sopenharmony_ci struct scsi_cmnd *scmnd, s32 req_lim_delta) 125362306a36Sopenharmony_ci{ 125462306a36Sopenharmony_ci unsigned long flags; 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci srp_unmap_data(scmnd, ch, req); 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci spin_lock_irqsave(&ch->lock, flags); 125962306a36Sopenharmony_ci ch->req_lim += req_lim_delta; 126062306a36Sopenharmony_ci spin_unlock_irqrestore(&ch->lock, flags); 126162306a36Sopenharmony_ci} 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_cistatic void srp_finish_req(struct srp_rdma_ch *ch, struct srp_request *req, 126462306a36Sopenharmony_ci struct scsi_device *sdev, int result) 126562306a36Sopenharmony_ci{ 126662306a36Sopenharmony_ci struct scsi_cmnd *scmnd = srp_claim_req(ch, req, sdev, NULL); 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci if (scmnd) { 126962306a36Sopenharmony_ci srp_free_req(ch, req, scmnd, 0); 127062306a36Sopenharmony_ci scmnd->result = result; 127162306a36Sopenharmony_ci scsi_done(scmnd); 127262306a36Sopenharmony_ci } 127362306a36Sopenharmony_ci} 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_cistruct srp_terminate_context { 127662306a36Sopenharmony_ci struct srp_target_port *srp_target; 127762306a36Sopenharmony_ci int scsi_result; 127862306a36Sopenharmony_ci}; 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_cistatic bool srp_terminate_cmd(struct scsi_cmnd *scmnd, void *context_ptr) 128162306a36Sopenharmony_ci{ 128262306a36Sopenharmony_ci struct srp_terminate_context *context = context_ptr; 128362306a36Sopenharmony_ci struct srp_target_port *target = context->srp_target; 128462306a36Sopenharmony_ci u32 tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmnd)); 128562306a36Sopenharmony_ci struct srp_rdma_ch *ch = &target->ch[blk_mq_unique_tag_to_hwq(tag)]; 128662306a36Sopenharmony_ci struct srp_request *req = scsi_cmd_priv(scmnd); 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci srp_finish_req(ch, req, NULL, context->scsi_result); 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci return true; 129162306a36Sopenharmony_ci} 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_cistatic void srp_terminate_io(struct srp_rport *rport) 129462306a36Sopenharmony_ci{ 129562306a36Sopenharmony_ci struct srp_target_port *target = rport->lld_data; 129662306a36Sopenharmony_ci struct srp_terminate_context context = { .srp_target = target, 129762306a36Sopenharmony_ci .scsi_result = DID_TRANSPORT_FAILFAST << 16 }; 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci scsi_host_busy_iter(target->scsi_host, srp_terminate_cmd, &context); 130062306a36Sopenharmony_ci} 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci/* Calculate maximum initiator to target information unit length. */ 130362306a36Sopenharmony_cistatic uint32_t srp_max_it_iu_len(int cmd_sg_cnt, bool use_imm_data, 130462306a36Sopenharmony_ci uint32_t max_it_iu_size) 130562306a36Sopenharmony_ci{ 130662306a36Sopenharmony_ci uint32_t max_iu_len = sizeof(struct srp_cmd) + SRP_MAX_ADD_CDB_LEN + 130762306a36Sopenharmony_ci sizeof(struct srp_indirect_buf) + 130862306a36Sopenharmony_ci cmd_sg_cnt * sizeof(struct srp_direct_buf); 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci if (use_imm_data) 131162306a36Sopenharmony_ci max_iu_len = max(max_iu_len, SRP_IMM_DATA_OFFSET + 131262306a36Sopenharmony_ci srp_max_imm_data); 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci if (max_it_iu_size) 131562306a36Sopenharmony_ci max_iu_len = min(max_iu_len, max_it_iu_size); 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci pr_debug("max_iu_len = %d\n", max_iu_len); 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci return max_iu_len; 132062306a36Sopenharmony_ci} 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci/* 132362306a36Sopenharmony_ci * It is up to the caller to ensure that srp_rport_reconnect() calls are 132462306a36Sopenharmony_ci * serialized and that no concurrent srp_queuecommand(), srp_abort(), 132562306a36Sopenharmony_ci * srp_reset_device() or srp_reset_host() calls will occur while this function 132662306a36Sopenharmony_ci * is in progress. One way to realize that is not to call this function 132762306a36Sopenharmony_ci * directly but to call srp_reconnect_rport() instead since that last function 132862306a36Sopenharmony_ci * serializes calls of this function via rport->mutex and also blocks 132962306a36Sopenharmony_ci * srp_queuecommand() calls before invoking this function. 133062306a36Sopenharmony_ci */ 133162306a36Sopenharmony_cistatic int srp_rport_reconnect(struct srp_rport *rport) 133262306a36Sopenharmony_ci{ 133362306a36Sopenharmony_ci struct srp_target_port *target = rport->lld_data; 133462306a36Sopenharmony_ci struct srp_rdma_ch *ch; 133562306a36Sopenharmony_ci uint32_t max_iu_len = srp_max_it_iu_len(target->cmd_sg_cnt, 133662306a36Sopenharmony_ci srp_use_imm_data, 133762306a36Sopenharmony_ci target->max_it_iu_size); 133862306a36Sopenharmony_ci int i, j, ret = 0; 133962306a36Sopenharmony_ci bool multich = false; 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci srp_disconnect_target(target); 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci if (target->state == SRP_TARGET_SCANNING) 134462306a36Sopenharmony_ci return -ENODEV; 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci /* 134762306a36Sopenharmony_ci * Now get a new local CM ID so that we avoid confusing the target in 134862306a36Sopenharmony_ci * case things are really fouled up. Doing so also ensures that all CM 134962306a36Sopenharmony_ci * callbacks will have finished before a new QP is allocated. 135062306a36Sopenharmony_ci */ 135162306a36Sopenharmony_ci for (i = 0; i < target->ch_count; i++) { 135262306a36Sopenharmony_ci ch = &target->ch[i]; 135362306a36Sopenharmony_ci ret += srp_new_cm_id(ch); 135462306a36Sopenharmony_ci } 135562306a36Sopenharmony_ci { 135662306a36Sopenharmony_ci struct srp_terminate_context context = { 135762306a36Sopenharmony_ci .srp_target = target, .scsi_result = DID_RESET << 16}; 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci scsi_host_busy_iter(target->scsi_host, srp_terminate_cmd, 136062306a36Sopenharmony_ci &context); 136162306a36Sopenharmony_ci } 136262306a36Sopenharmony_ci for (i = 0; i < target->ch_count; i++) { 136362306a36Sopenharmony_ci ch = &target->ch[i]; 136462306a36Sopenharmony_ci /* 136562306a36Sopenharmony_ci * Whether or not creating a new CM ID succeeded, create a new 136662306a36Sopenharmony_ci * QP. This guarantees that all completion callback function 136762306a36Sopenharmony_ci * invocations have finished before request resetting starts. 136862306a36Sopenharmony_ci */ 136962306a36Sopenharmony_ci ret += srp_create_ch_ib(ch); 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci INIT_LIST_HEAD(&ch->free_tx); 137262306a36Sopenharmony_ci for (j = 0; j < target->queue_size; ++j) 137362306a36Sopenharmony_ci list_add(&ch->tx_ring[j]->list, &ch->free_tx); 137462306a36Sopenharmony_ci } 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci target->qp_in_error = false; 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci for (i = 0; i < target->ch_count; i++) { 137962306a36Sopenharmony_ci ch = &target->ch[i]; 138062306a36Sopenharmony_ci if (ret) 138162306a36Sopenharmony_ci break; 138262306a36Sopenharmony_ci ret = srp_connect_ch(ch, max_iu_len, multich); 138362306a36Sopenharmony_ci multich = true; 138462306a36Sopenharmony_ci } 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci if (ret == 0) 138762306a36Sopenharmony_ci shost_printk(KERN_INFO, target->scsi_host, 138862306a36Sopenharmony_ci PFX "reconnect succeeded\n"); 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci return ret; 139162306a36Sopenharmony_ci} 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_cistatic void srp_map_desc(struct srp_map_state *state, dma_addr_t dma_addr, 139462306a36Sopenharmony_ci unsigned int dma_len, u32 rkey) 139562306a36Sopenharmony_ci{ 139662306a36Sopenharmony_ci struct srp_direct_buf *desc = state->desc; 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci WARN_ON_ONCE(!dma_len); 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci desc->va = cpu_to_be64(dma_addr); 140162306a36Sopenharmony_ci desc->key = cpu_to_be32(rkey); 140262306a36Sopenharmony_ci desc->len = cpu_to_be32(dma_len); 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci state->total_len += dma_len; 140562306a36Sopenharmony_ci state->desc++; 140662306a36Sopenharmony_ci state->ndesc++; 140762306a36Sopenharmony_ci} 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_cistatic void srp_reg_mr_err_done(struct ib_cq *cq, struct ib_wc *wc) 141062306a36Sopenharmony_ci{ 141162306a36Sopenharmony_ci srp_handle_qp_err(cq, wc, "FAST REG"); 141262306a36Sopenharmony_ci} 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci/* 141562306a36Sopenharmony_ci * Map up to sg_nents elements of state->sg where *sg_offset_p is the offset 141662306a36Sopenharmony_ci * where to start in the first element. If sg_offset_p != NULL then 141762306a36Sopenharmony_ci * *sg_offset_p is updated to the offset in state->sg[retval] of the first 141862306a36Sopenharmony_ci * byte that has not yet been mapped. 141962306a36Sopenharmony_ci */ 142062306a36Sopenharmony_cistatic int srp_map_finish_fr(struct srp_map_state *state, 142162306a36Sopenharmony_ci struct srp_request *req, 142262306a36Sopenharmony_ci struct srp_rdma_ch *ch, int sg_nents, 142362306a36Sopenharmony_ci unsigned int *sg_offset_p) 142462306a36Sopenharmony_ci{ 142562306a36Sopenharmony_ci struct srp_target_port *target = ch->target; 142662306a36Sopenharmony_ci struct srp_device *dev = target->srp_host->srp_dev; 142762306a36Sopenharmony_ci struct ib_reg_wr wr; 142862306a36Sopenharmony_ci struct srp_fr_desc *desc; 142962306a36Sopenharmony_ci u32 rkey; 143062306a36Sopenharmony_ci int n, err; 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci if (state->fr.next >= state->fr.end) { 143362306a36Sopenharmony_ci shost_printk(KERN_ERR, ch->target->scsi_host, 143462306a36Sopenharmony_ci PFX "Out of MRs (mr_per_cmd = %d)\n", 143562306a36Sopenharmony_ci ch->target->mr_per_cmd); 143662306a36Sopenharmony_ci return -ENOMEM; 143762306a36Sopenharmony_ci } 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci WARN_ON_ONCE(!dev->use_fast_reg); 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci if (sg_nents == 1 && target->global_rkey) { 144262306a36Sopenharmony_ci unsigned int sg_offset = sg_offset_p ? *sg_offset_p : 0; 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci srp_map_desc(state, sg_dma_address(state->sg) + sg_offset, 144562306a36Sopenharmony_ci sg_dma_len(state->sg) - sg_offset, 144662306a36Sopenharmony_ci target->global_rkey); 144762306a36Sopenharmony_ci if (sg_offset_p) 144862306a36Sopenharmony_ci *sg_offset_p = 0; 144962306a36Sopenharmony_ci return 1; 145062306a36Sopenharmony_ci } 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci desc = srp_fr_pool_get(ch->fr_pool); 145362306a36Sopenharmony_ci if (!desc) 145462306a36Sopenharmony_ci return -ENOMEM; 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci rkey = ib_inc_rkey(desc->mr->rkey); 145762306a36Sopenharmony_ci ib_update_fast_reg_key(desc->mr, rkey); 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci n = ib_map_mr_sg(desc->mr, state->sg, sg_nents, sg_offset_p, 146062306a36Sopenharmony_ci dev->mr_page_size); 146162306a36Sopenharmony_ci if (unlikely(n < 0)) { 146262306a36Sopenharmony_ci srp_fr_pool_put(ch->fr_pool, &desc, 1); 146362306a36Sopenharmony_ci pr_debug("%s: ib_map_mr_sg(%d, %d) returned %d.\n", 146462306a36Sopenharmony_ci dev_name(&req->scmnd->device->sdev_gendev), sg_nents, 146562306a36Sopenharmony_ci sg_offset_p ? *sg_offset_p : -1, n); 146662306a36Sopenharmony_ci return n; 146762306a36Sopenharmony_ci } 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci WARN_ON_ONCE(desc->mr->length == 0); 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci req->reg_cqe.done = srp_reg_mr_err_done; 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci wr.wr.next = NULL; 147462306a36Sopenharmony_ci wr.wr.opcode = IB_WR_REG_MR; 147562306a36Sopenharmony_ci wr.wr.wr_cqe = &req->reg_cqe; 147662306a36Sopenharmony_ci wr.wr.num_sge = 0; 147762306a36Sopenharmony_ci wr.wr.send_flags = 0; 147862306a36Sopenharmony_ci wr.mr = desc->mr; 147962306a36Sopenharmony_ci wr.key = desc->mr->rkey; 148062306a36Sopenharmony_ci wr.access = (IB_ACCESS_LOCAL_WRITE | 148162306a36Sopenharmony_ci IB_ACCESS_REMOTE_READ | 148262306a36Sopenharmony_ci IB_ACCESS_REMOTE_WRITE); 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci *state->fr.next++ = desc; 148562306a36Sopenharmony_ci state->nmdesc++; 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci srp_map_desc(state, desc->mr->iova, 148862306a36Sopenharmony_ci desc->mr->length, desc->mr->rkey); 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci err = ib_post_send(ch->qp, &wr.wr, NULL); 149162306a36Sopenharmony_ci if (unlikely(err)) { 149262306a36Sopenharmony_ci WARN_ON_ONCE(err == -ENOMEM); 149362306a36Sopenharmony_ci return err; 149462306a36Sopenharmony_ci } 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci return n; 149762306a36Sopenharmony_ci} 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_cistatic int srp_map_sg_fr(struct srp_map_state *state, struct srp_rdma_ch *ch, 150062306a36Sopenharmony_ci struct srp_request *req, struct scatterlist *scat, 150162306a36Sopenharmony_ci int count) 150262306a36Sopenharmony_ci{ 150362306a36Sopenharmony_ci unsigned int sg_offset = 0; 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci state->fr.next = req->fr_list; 150662306a36Sopenharmony_ci state->fr.end = req->fr_list + ch->target->mr_per_cmd; 150762306a36Sopenharmony_ci state->sg = scat; 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ci if (count == 0) 151062306a36Sopenharmony_ci return 0; 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci while (count) { 151362306a36Sopenharmony_ci int i, n; 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci n = srp_map_finish_fr(state, req, ch, count, &sg_offset); 151662306a36Sopenharmony_ci if (unlikely(n < 0)) 151762306a36Sopenharmony_ci return n; 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_ci count -= n; 152062306a36Sopenharmony_ci for (i = 0; i < n; i++) 152162306a36Sopenharmony_ci state->sg = sg_next(state->sg); 152262306a36Sopenharmony_ci } 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci return 0; 152562306a36Sopenharmony_ci} 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_cistatic int srp_map_sg_dma(struct srp_map_state *state, struct srp_rdma_ch *ch, 152862306a36Sopenharmony_ci struct srp_request *req, struct scatterlist *scat, 152962306a36Sopenharmony_ci int count) 153062306a36Sopenharmony_ci{ 153162306a36Sopenharmony_ci struct srp_target_port *target = ch->target; 153262306a36Sopenharmony_ci struct scatterlist *sg; 153362306a36Sopenharmony_ci int i; 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci for_each_sg(scat, sg, count, i) { 153662306a36Sopenharmony_ci srp_map_desc(state, sg_dma_address(sg), sg_dma_len(sg), 153762306a36Sopenharmony_ci target->global_rkey); 153862306a36Sopenharmony_ci } 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci return 0; 154162306a36Sopenharmony_ci} 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci/* 154462306a36Sopenharmony_ci * Register the indirect data buffer descriptor with the HCA. 154562306a36Sopenharmony_ci * 154662306a36Sopenharmony_ci * Note: since the indirect data buffer descriptor has been allocated with 154762306a36Sopenharmony_ci * kmalloc() it is guaranteed that this buffer is a physically contiguous 154862306a36Sopenharmony_ci * memory buffer. 154962306a36Sopenharmony_ci */ 155062306a36Sopenharmony_cistatic int srp_map_idb(struct srp_rdma_ch *ch, struct srp_request *req, 155162306a36Sopenharmony_ci void **next_mr, void **end_mr, u32 idb_len, 155262306a36Sopenharmony_ci __be32 *idb_rkey) 155362306a36Sopenharmony_ci{ 155462306a36Sopenharmony_ci struct srp_target_port *target = ch->target; 155562306a36Sopenharmony_ci struct srp_device *dev = target->srp_host->srp_dev; 155662306a36Sopenharmony_ci struct srp_map_state state; 155762306a36Sopenharmony_ci struct srp_direct_buf idb_desc; 155862306a36Sopenharmony_ci struct scatterlist idb_sg[1]; 155962306a36Sopenharmony_ci int ret; 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci memset(&state, 0, sizeof(state)); 156262306a36Sopenharmony_ci memset(&idb_desc, 0, sizeof(idb_desc)); 156362306a36Sopenharmony_ci state.gen.next = next_mr; 156462306a36Sopenharmony_ci state.gen.end = end_mr; 156562306a36Sopenharmony_ci state.desc = &idb_desc; 156662306a36Sopenharmony_ci state.base_dma_addr = req->indirect_dma_addr; 156762306a36Sopenharmony_ci state.dma_len = idb_len; 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci if (dev->use_fast_reg) { 157062306a36Sopenharmony_ci state.sg = idb_sg; 157162306a36Sopenharmony_ci sg_init_one(idb_sg, req->indirect_desc, idb_len); 157262306a36Sopenharmony_ci idb_sg->dma_address = req->indirect_dma_addr; /* hack! */ 157362306a36Sopenharmony_ci#ifdef CONFIG_NEED_SG_DMA_LENGTH 157462306a36Sopenharmony_ci idb_sg->dma_length = idb_sg->length; /* hack^2 */ 157562306a36Sopenharmony_ci#endif 157662306a36Sopenharmony_ci ret = srp_map_finish_fr(&state, req, ch, 1, NULL); 157762306a36Sopenharmony_ci if (ret < 0) 157862306a36Sopenharmony_ci return ret; 157962306a36Sopenharmony_ci WARN_ON_ONCE(ret < 1); 158062306a36Sopenharmony_ci } else { 158162306a36Sopenharmony_ci return -EINVAL; 158262306a36Sopenharmony_ci } 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci *idb_rkey = idb_desc.key; 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci return 0; 158762306a36Sopenharmony_ci} 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_cistatic void srp_check_mapping(struct srp_map_state *state, 159062306a36Sopenharmony_ci struct srp_rdma_ch *ch, struct srp_request *req, 159162306a36Sopenharmony_ci struct scatterlist *scat, int count) 159262306a36Sopenharmony_ci{ 159362306a36Sopenharmony_ci struct srp_device *dev = ch->target->srp_host->srp_dev; 159462306a36Sopenharmony_ci struct srp_fr_desc **pfr; 159562306a36Sopenharmony_ci u64 desc_len = 0, mr_len = 0; 159662306a36Sopenharmony_ci int i; 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci for (i = 0; i < state->ndesc; i++) 159962306a36Sopenharmony_ci desc_len += be32_to_cpu(req->indirect_desc[i].len); 160062306a36Sopenharmony_ci if (dev->use_fast_reg) 160162306a36Sopenharmony_ci for (i = 0, pfr = req->fr_list; i < state->nmdesc; i++, pfr++) 160262306a36Sopenharmony_ci mr_len += (*pfr)->mr->length; 160362306a36Sopenharmony_ci if (desc_len != scsi_bufflen(req->scmnd) || 160462306a36Sopenharmony_ci mr_len > scsi_bufflen(req->scmnd)) 160562306a36Sopenharmony_ci pr_err("Inconsistent: scsi len %d <> desc len %lld <> mr len %lld; ndesc %d; nmdesc = %d\n", 160662306a36Sopenharmony_ci scsi_bufflen(req->scmnd), desc_len, mr_len, 160762306a36Sopenharmony_ci state->ndesc, state->nmdesc); 160862306a36Sopenharmony_ci} 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci/** 161162306a36Sopenharmony_ci * srp_map_data() - map SCSI data buffer onto an SRP request 161262306a36Sopenharmony_ci * @scmnd: SCSI command to map 161362306a36Sopenharmony_ci * @ch: SRP RDMA channel 161462306a36Sopenharmony_ci * @req: SRP request 161562306a36Sopenharmony_ci * 161662306a36Sopenharmony_ci * Returns the length in bytes of the SRP_CMD IU or a negative value if 161762306a36Sopenharmony_ci * mapping failed. The size of any immediate data is not included in the 161862306a36Sopenharmony_ci * return value. 161962306a36Sopenharmony_ci */ 162062306a36Sopenharmony_cistatic int srp_map_data(struct scsi_cmnd *scmnd, struct srp_rdma_ch *ch, 162162306a36Sopenharmony_ci struct srp_request *req) 162262306a36Sopenharmony_ci{ 162362306a36Sopenharmony_ci struct srp_target_port *target = ch->target; 162462306a36Sopenharmony_ci struct scatterlist *scat, *sg; 162562306a36Sopenharmony_ci struct srp_cmd *cmd = req->cmd->buf; 162662306a36Sopenharmony_ci int i, len, nents, count, ret; 162762306a36Sopenharmony_ci struct srp_device *dev; 162862306a36Sopenharmony_ci struct ib_device *ibdev; 162962306a36Sopenharmony_ci struct srp_map_state state; 163062306a36Sopenharmony_ci struct srp_indirect_buf *indirect_hdr; 163162306a36Sopenharmony_ci u64 data_len; 163262306a36Sopenharmony_ci u32 idb_len, table_len; 163362306a36Sopenharmony_ci __be32 idb_rkey; 163462306a36Sopenharmony_ci u8 fmt; 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci req->cmd->num_sge = 1; 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci if (!scsi_sglist(scmnd) || scmnd->sc_data_direction == DMA_NONE) 163962306a36Sopenharmony_ci return sizeof(struct srp_cmd) + cmd->add_cdb_len; 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ci if (scmnd->sc_data_direction != DMA_FROM_DEVICE && 164262306a36Sopenharmony_ci scmnd->sc_data_direction != DMA_TO_DEVICE) { 164362306a36Sopenharmony_ci shost_printk(KERN_WARNING, target->scsi_host, 164462306a36Sopenharmony_ci PFX "Unhandled data direction %d\n", 164562306a36Sopenharmony_ci scmnd->sc_data_direction); 164662306a36Sopenharmony_ci return -EINVAL; 164762306a36Sopenharmony_ci } 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_ci nents = scsi_sg_count(scmnd); 165062306a36Sopenharmony_ci scat = scsi_sglist(scmnd); 165162306a36Sopenharmony_ci data_len = scsi_bufflen(scmnd); 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci dev = target->srp_host->srp_dev; 165462306a36Sopenharmony_ci ibdev = dev->dev; 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_ci count = ib_dma_map_sg(ibdev, scat, nents, scmnd->sc_data_direction); 165762306a36Sopenharmony_ci if (unlikely(count == 0)) 165862306a36Sopenharmony_ci return -EIO; 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_ci if (ch->use_imm_data && 166162306a36Sopenharmony_ci count <= ch->max_imm_sge && 166262306a36Sopenharmony_ci SRP_IMM_DATA_OFFSET + data_len <= ch->max_it_iu_len && 166362306a36Sopenharmony_ci scmnd->sc_data_direction == DMA_TO_DEVICE) { 166462306a36Sopenharmony_ci struct srp_imm_buf *buf; 166562306a36Sopenharmony_ci struct ib_sge *sge = &req->cmd->sge[1]; 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci fmt = SRP_DATA_DESC_IMM; 166862306a36Sopenharmony_ci len = SRP_IMM_DATA_OFFSET; 166962306a36Sopenharmony_ci req->nmdesc = 0; 167062306a36Sopenharmony_ci buf = (void *)cmd->add_data + cmd->add_cdb_len; 167162306a36Sopenharmony_ci buf->len = cpu_to_be32(data_len); 167262306a36Sopenharmony_ci WARN_ON_ONCE((void *)(buf + 1) > (void *)cmd + len); 167362306a36Sopenharmony_ci for_each_sg(scat, sg, count, i) { 167462306a36Sopenharmony_ci sge[i].addr = sg_dma_address(sg); 167562306a36Sopenharmony_ci sge[i].length = sg_dma_len(sg); 167662306a36Sopenharmony_ci sge[i].lkey = target->lkey; 167762306a36Sopenharmony_ci } 167862306a36Sopenharmony_ci req->cmd->num_sge += count; 167962306a36Sopenharmony_ci goto map_complete; 168062306a36Sopenharmony_ci } 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci fmt = SRP_DATA_DESC_DIRECT; 168362306a36Sopenharmony_ci len = sizeof(struct srp_cmd) + cmd->add_cdb_len + 168462306a36Sopenharmony_ci sizeof(struct srp_direct_buf); 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_ci if (count == 1 && target->global_rkey) { 168762306a36Sopenharmony_ci /* 168862306a36Sopenharmony_ci * The midlayer only generated a single gather/scatter 168962306a36Sopenharmony_ci * entry, or DMA mapping coalesced everything to a 169062306a36Sopenharmony_ci * single entry. So a direct descriptor along with 169162306a36Sopenharmony_ci * the DMA MR suffices. 169262306a36Sopenharmony_ci */ 169362306a36Sopenharmony_ci struct srp_direct_buf *buf; 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_ci buf = (void *)cmd->add_data + cmd->add_cdb_len; 169662306a36Sopenharmony_ci buf->va = cpu_to_be64(sg_dma_address(scat)); 169762306a36Sopenharmony_ci buf->key = cpu_to_be32(target->global_rkey); 169862306a36Sopenharmony_ci buf->len = cpu_to_be32(sg_dma_len(scat)); 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci req->nmdesc = 0; 170162306a36Sopenharmony_ci goto map_complete; 170262306a36Sopenharmony_ci } 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ci /* 170562306a36Sopenharmony_ci * We have more than one scatter/gather entry, so build our indirect 170662306a36Sopenharmony_ci * descriptor table, trying to merge as many entries as we can. 170762306a36Sopenharmony_ci */ 170862306a36Sopenharmony_ci indirect_hdr = (void *)cmd->add_data + cmd->add_cdb_len; 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_ci ib_dma_sync_single_for_cpu(ibdev, req->indirect_dma_addr, 171162306a36Sopenharmony_ci target->indirect_size, DMA_TO_DEVICE); 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci memset(&state, 0, sizeof(state)); 171462306a36Sopenharmony_ci state.desc = req->indirect_desc; 171562306a36Sopenharmony_ci if (dev->use_fast_reg) 171662306a36Sopenharmony_ci ret = srp_map_sg_fr(&state, ch, req, scat, count); 171762306a36Sopenharmony_ci else 171862306a36Sopenharmony_ci ret = srp_map_sg_dma(&state, ch, req, scat, count); 171962306a36Sopenharmony_ci req->nmdesc = state.nmdesc; 172062306a36Sopenharmony_ci if (ret < 0) 172162306a36Sopenharmony_ci goto unmap; 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_ci { 172462306a36Sopenharmony_ci DEFINE_DYNAMIC_DEBUG_METADATA(ddm, 172562306a36Sopenharmony_ci "Memory mapping consistency check"); 172662306a36Sopenharmony_ci if (DYNAMIC_DEBUG_BRANCH(ddm)) 172762306a36Sopenharmony_ci srp_check_mapping(&state, ch, req, scat, count); 172862306a36Sopenharmony_ci } 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_ci /* We've mapped the request, now pull as much of the indirect 173162306a36Sopenharmony_ci * descriptor table as we can into the command buffer. If this 173262306a36Sopenharmony_ci * target is not using an external indirect table, we are 173362306a36Sopenharmony_ci * guaranteed to fit into the command, as the SCSI layer won't 173462306a36Sopenharmony_ci * give us more S/G entries than we allow. 173562306a36Sopenharmony_ci */ 173662306a36Sopenharmony_ci if (state.ndesc == 1) { 173762306a36Sopenharmony_ci /* 173862306a36Sopenharmony_ci * Memory registration collapsed the sg-list into one entry, 173962306a36Sopenharmony_ci * so use a direct descriptor. 174062306a36Sopenharmony_ci */ 174162306a36Sopenharmony_ci struct srp_direct_buf *buf; 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci buf = (void *)cmd->add_data + cmd->add_cdb_len; 174462306a36Sopenharmony_ci *buf = req->indirect_desc[0]; 174562306a36Sopenharmony_ci goto map_complete; 174662306a36Sopenharmony_ci } 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_ci if (unlikely(target->cmd_sg_cnt < state.ndesc && 174962306a36Sopenharmony_ci !target->allow_ext_sg)) { 175062306a36Sopenharmony_ci shost_printk(KERN_ERR, target->scsi_host, 175162306a36Sopenharmony_ci "Could not fit S/G list into SRP_CMD\n"); 175262306a36Sopenharmony_ci ret = -EIO; 175362306a36Sopenharmony_ci goto unmap; 175462306a36Sopenharmony_ci } 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_ci count = min(state.ndesc, target->cmd_sg_cnt); 175762306a36Sopenharmony_ci table_len = state.ndesc * sizeof (struct srp_direct_buf); 175862306a36Sopenharmony_ci idb_len = sizeof(struct srp_indirect_buf) + table_len; 175962306a36Sopenharmony_ci 176062306a36Sopenharmony_ci fmt = SRP_DATA_DESC_INDIRECT; 176162306a36Sopenharmony_ci len = sizeof(struct srp_cmd) + cmd->add_cdb_len + 176262306a36Sopenharmony_ci sizeof(struct srp_indirect_buf); 176362306a36Sopenharmony_ci len += count * sizeof (struct srp_direct_buf); 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_ci memcpy(indirect_hdr->desc_list, req->indirect_desc, 176662306a36Sopenharmony_ci count * sizeof (struct srp_direct_buf)); 176762306a36Sopenharmony_ci 176862306a36Sopenharmony_ci if (!target->global_rkey) { 176962306a36Sopenharmony_ci ret = srp_map_idb(ch, req, state.gen.next, state.gen.end, 177062306a36Sopenharmony_ci idb_len, &idb_rkey); 177162306a36Sopenharmony_ci if (ret < 0) 177262306a36Sopenharmony_ci goto unmap; 177362306a36Sopenharmony_ci req->nmdesc++; 177462306a36Sopenharmony_ci } else { 177562306a36Sopenharmony_ci idb_rkey = cpu_to_be32(target->global_rkey); 177662306a36Sopenharmony_ci } 177762306a36Sopenharmony_ci 177862306a36Sopenharmony_ci indirect_hdr->table_desc.va = cpu_to_be64(req->indirect_dma_addr); 177962306a36Sopenharmony_ci indirect_hdr->table_desc.key = idb_rkey; 178062306a36Sopenharmony_ci indirect_hdr->table_desc.len = cpu_to_be32(table_len); 178162306a36Sopenharmony_ci indirect_hdr->len = cpu_to_be32(state.total_len); 178262306a36Sopenharmony_ci 178362306a36Sopenharmony_ci if (scmnd->sc_data_direction == DMA_TO_DEVICE) 178462306a36Sopenharmony_ci cmd->data_out_desc_cnt = count; 178562306a36Sopenharmony_ci else 178662306a36Sopenharmony_ci cmd->data_in_desc_cnt = count; 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ci ib_dma_sync_single_for_device(ibdev, req->indirect_dma_addr, table_len, 178962306a36Sopenharmony_ci DMA_TO_DEVICE); 179062306a36Sopenharmony_ci 179162306a36Sopenharmony_cimap_complete: 179262306a36Sopenharmony_ci if (scmnd->sc_data_direction == DMA_TO_DEVICE) 179362306a36Sopenharmony_ci cmd->buf_fmt = fmt << 4; 179462306a36Sopenharmony_ci else 179562306a36Sopenharmony_ci cmd->buf_fmt = fmt; 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_ci return len; 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_ciunmap: 180062306a36Sopenharmony_ci srp_unmap_data(scmnd, ch, req); 180162306a36Sopenharmony_ci if (ret == -ENOMEM && req->nmdesc >= target->mr_pool_size) 180262306a36Sopenharmony_ci ret = -E2BIG; 180362306a36Sopenharmony_ci return ret; 180462306a36Sopenharmony_ci} 180562306a36Sopenharmony_ci 180662306a36Sopenharmony_ci/* 180762306a36Sopenharmony_ci * Return an IU and possible credit to the free pool 180862306a36Sopenharmony_ci */ 180962306a36Sopenharmony_cistatic void srp_put_tx_iu(struct srp_rdma_ch *ch, struct srp_iu *iu, 181062306a36Sopenharmony_ci enum srp_iu_type iu_type) 181162306a36Sopenharmony_ci{ 181262306a36Sopenharmony_ci unsigned long flags; 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_ci spin_lock_irqsave(&ch->lock, flags); 181562306a36Sopenharmony_ci list_add(&iu->list, &ch->free_tx); 181662306a36Sopenharmony_ci if (iu_type != SRP_IU_RSP) 181762306a36Sopenharmony_ci ++ch->req_lim; 181862306a36Sopenharmony_ci spin_unlock_irqrestore(&ch->lock, flags); 181962306a36Sopenharmony_ci} 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_ci/* 182262306a36Sopenharmony_ci * Must be called with ch->lock held to protect req_lim and free_tx. 182362306a36Sopenharmony_ci * If IU is not sent, it must be returned using srp_put_tx_iu(). 182462306a36Sopenharmony_ci * 182562306a36Sopenharmony_ci * Note: 182662306a36Sopenharmony_ci * An upper limit for the number of allocated information units for each 182762306a36Sopenharmony_ci * request type is: 182862306a36Sopenharmony_ci * - SRP_IU_CMD: SRP_CMD_SQ_SIZE, since the SCSI mid-layer never queues 182962306a36Sopenharmony_ci * more than Scsi_Host.can_queue requests. 183062306a36Sopenharmony_ci * - SRP_IU_TSK_MGMT: SRP_TSK_MGMT_SQ_SIZE. 183162306a36Sopenharmony_ci * - SRP_IU_RSP: 1, since a conforming SRP target never sends more than 183262306a36Sopenharmony_ci * one unanswered SRP request to an initiator. 183362306a36Sopenharmony_ci */ 183462306a36Sopenharmony_cistatic struct srp_iu *__srp_get_tx_iu(struct srp_rdma_ch *ch, 183562306a36Sopenharmony_ci enum srp_iu_type iu_type) 183662306a36Sopenharmony_ci{ 183762306a36Sopenharmony_ci struct srp_target_port *target = ch->target; 183862306a36Sopenharmony_ci s32 rsv = (iu_type == SRP_IU_TSK_MGMT) ? 0 : SRP_TSK_MGMT_SQ_SIZE; 183962306a36Sopenharmony_ci struct srp_iu *iu; 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci lockdep_assert_held(&ch->lock); 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_ci ib_process_cq_direct(ch->send_cq, -1); 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ci if (list_empty(&ch->free_tx)) 184662306a36Sopenharmony_ci return NULL; 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_ci /* Initiator responses to target requests do not consume credits */ 184962306a36Sopenharmony_ci if (iu_type != SRP_IU_RSP) { 185062306a36Sopenharmony_ci if (ch->req_lim <= rsv) { 185162306a36Sopenharmony_ci ++target->zero_req_lim; 185262306a36Sopenharmony_ci return NULL; 185362306a36Sopenharmony_ci } 185462306a36Sopenharmony_ci 185562306a36Sopenharmony_ci --ch->req_lim; 185662306a36Sopenharmony_ci } 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_ci iu = list_first_entry(&ch->free_tx, struct srp_iu, list); 185962306a36Sopenharmony_ci list_del(&iu->list); 186062306a36Sopenharmony_ci return iu; 186162306a36Sopenharmony_ci} 186262306a36Sopenharmony_ci 186362306a36Sopenharmony_ci/* 186462306a36Sopenharmony_ci * Note: if this function is called from inside ib_drain_sq() then it will 186562306a36Sopenharmony_ci * be called without ch->lock being held. If ib_drain_sq() dequeues a WQE 186662306a36Sopenharmony_ci * with status IB_WC_SUCCESS then that's a bug. 186762306a36Sopenharmony_ci */ 186862306a36Sopenharmony_cistatic void srp_send_done(struct ib_cq *cq, struct ib_wc *wc) 186962306a36Sopenharmony_ci{ 187062306a36Sopenharmony_ci struct srp_iu *iu = container_of(wc->wr_cqe, struct srp_iu, cqe); 187162306a36Sopenharmony_ci struct srp_rdma_ch *ch = cq->cq_context; 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ci if (unlikely(wc->status != IB_WC_SUCCESS)) { 187462306a36Sopenharmony_ci srp_handle_qp_err(cq, wc, "SEND"); 187562306a36Sopenharmony_ci return; 187662306a36Sopenharmony_ci } 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci lockdep_assert_held(&ch->lock); 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci list_add(&iu->list, &ch->free_tx); 188162306a36Sopenharmony_ci} 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_ci/** 188462306a36Sopenharmony_ci * srp_post_send() - send an SRP information unit 188562306a36Sopenharmony_ci * @ch: RDMA channel over which to send the information unit. 188662306a36Sopenharmony_ci * @iu: Information unit to send. 188762306a36Sopenharmony_ci * @len: Length of the information unit excluding immediate data. 188862306a36Sopenharmony_ci */ 188962306a36Sopenharmony_cistatic int srp_post_send(struct srp_rdma_ch *ch, struct srp_iu *iu, int len) 189062306a36Sopenharmony_ci{ 189162306a36Sopenharmony_ci struct srp_target_port *target = ch->target; 189262306a36Sopenharmony_ci struct ib_send_wr wr; 189362306a36Sopenharmony_ci 189462306a36Sopenharmony_ci if (WARN_ON_ONCE(iu->num_sge > SRP_MAX_SGE)) 189562306a36Sopenharmony_ci return -EINVAL; 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_ci iu->sge[0].addr = iu->dma; 189862306a36Sopenharmony_ci iu->sge[0].length = len; 189962306a36Sopenharmony_ci iu->sge[0].lkey = target->lkey; 190062306a36Sopenharmony_ci 190162306a36Sopenharmony_ci iu->cqe.done = srp_send_done; 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_ci wr.next = NULL; 190462306a36Sopenharmony_ci wr.wr_cqe = &iu->cqe; 190562306a36Sopenharmony_ci wr.sg_list = &iu->sge[0]; 190662306a36Sopenharmony_ci wr.num_sge = iu->num_sge; 190762306a36Sopenharmony_ci wr.opcode = IB_WR_SEND; 190862306a36Sopenharmony_ci wr.send_flags = IB_SEND_SIGNALED; 190962306a36Sopenharmony_ci 191062306a36Sopenharmony_ci return ib_post_send(ch->qp, &wr, NULL); 191162306a36Sopenharmony_ci} 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_cistatic int srp_post_recv(struct srp_rdma_ch *ch, struct srp_iu *iu) 191462306a36Sopenharmony_ci{ 191562306a36Sopenharmony_ci struct srp_target_port *target = ch->target; 191662306a36Sopenharmony_ci struct ib_recv_wr wr; 191762306a36Sopenharmony_ci struct ib_sge list; 191862306a36Sopenharmony_ci 191962306a36Sopenharmony_ci list.addr = iu->dma; 192062306a36Sopenharmony_ci list.length = iu->size; 192162306a36Sopenharmony_ci list.lkey = target->lkey; 192262306a36Sopenharmony_ci 192362306a36Sopenharmony_ci iu->cqe.done = srp_recv_done; 192462306a36Sopenharmony_ci 192562306a36Sopenharmony_ci wr.next = NULL; 192662306a36Sopenharmony_ci wr.wr_cqe = &iu->cqe; 192762306a36Sopenharmony_ci wr.sg_list = &list; 192862306a36Sopenharmony_ci wr.num_sge = 1; 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_ci return ib_post_recv(ch->qp, &wr, NULL); 193162306a36Sopenharmony_ci} 193262306a36Sopenharmony_ci 193362306a36Sopenharmony_cistatic void srp_process_rsp(struct srp_rdma_ch *ch, struct srp_rsp *rsp) 193462306a36Sopenharmony_ci{ 193562306a36Sopenharmony_ci struct srp_target_port *target = ch->target; 193662306a36Sopenharmony_ci struct srp_request *req; 193762306a36Sopenharmony_ci struct scsi_cmnd *scmnd; 193862306a36Sopenharmony_ci unsigned long flags; 193962306a36Sopenharmony_ci 194062306a36Sopenharmony_ci if (unlikely(rsp->tag & SRP_TAG_TSK_MGMT)) { 194162306a36Sopenharmony_ci spin_lock_irqsave(&ch->lock, flags); 194262306a36Sopenharmony_ci ch->req_lim += be32_to_cpu(rsp->req_lim_delta); 194362306a36Sopenharmony_ci if (rsp->tag == ch->tsk_mgmt_tag) { 194462306a36Sopenharmony_ci ch->tsk_mgmt_status = -1; 194562306a36Sopenharmony_ci if (be32_to_cpu(rsp->resp_data_len) >= 4) 194662306a36Sopenharmony_ci ch->tsk_mgmt_status = rsp->data[3]; 194762306a36Sopenharmony_ci complete(&ch->tsk_mgmt_done); 194862306a36Sopenharmony_ci } else { 194962306a36Sopenharmony_ci shost_printk(KERN_ERR, target->scsi_host, 195062306a36Sopenharmony_ci "Received tsk mgmt response too late for tag %#llx\n", 195162306a36Sopenharmony_ci rsp->tag); 195262306a36Sopenharmony_ci } 195362306a36Sopenharmony_ci spin_unlock_irqrestore(&ch->lock, flags); 195462306a36Sopenharmony_ci } else { 195562306a36Sopenharmony_ci scmnd = scsi_host_find_tag(target->scsi_host, rsp->tag); 195662306a36Sopenharmony_ci if (scmnd) { 195762306a36Sopenharmony_ci req = scsi_cmd_priv(scmnd); 195862306a36Sopenharmony_ci scmnd = srp_claim_req(ch, req, NULL, scmnd); 195962306a36Sopenharmony_ci } 196062306a36Sopenharmony_ci if (!scmnd) { 196162306a36Sopenharmony_ci shost_printk(KERN_ERR, target->scsi_host, 196262306a36Sopenharmony_ci "Null scmnd for RSP w/tag %#016llx received on ch %td / QP %#x\n", 196362306a36Sopenharmony_ci rsp->tag, ch - target->ch, ch->qp->qp_num); 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_ci spin_lock_irqsave(&ch->lock, flags); 196662306a36Sopenharmony_ci ch->req_lim += be32_to_cpu(rsp->req_lim_delta); 196762306a36Sopenharmony_ci spin_unlock_irqrestore(&ch->lock, flags); 196862306a36Sopenharmony_ci 196962306a36Sopenharmony_ci return; 197062306a36Sopenharmony_ci } 197162306a36Sopenharmony_ci scmnd->result = rsp->status; 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_ci if (rsp->flags & SRP_RSP_FLAG_SNSVALID) { 197462306a36Sopenharmony_ci memcpy(scmnd->sense_buffer, rsp->data + 197562306a36Sopenharmony_ci be32_to_cpu(rsp->resp_data_len), 197662306a36Sopenharmony_ci min_t(int, be32_to_cpu(rsp->sense_data_len), 197762306a36Sopenharmony_ci SCSI_SENSE_BUFFERSIZE)); 197862306a36Sopenharmony_ci } 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_ci if (unlikely(rsp->flags & SRP_RSP_FLAG_DIUNDER)) 198162306a36Sopenharmony_ci scsi_set_resid(scmnd, be32_to_cpu(rsp->data_in_res_cnt)); 198262306a36Sopenharmony_ci else if (unlikely(rsp->flags & SRP_RSP_FLAG_DOUNDER)) 198362306a36Sopenharmony_ci scsi_set_resid(scmnd, be32_to_cpu(rsp->data_out_res_cnt)); 198462306a36Sopenharmony_ci 198562306a36Sopenharmony_ci srp_free_req(ch, req, scmnd, 198662306a36Sopenharmony_ci be32_to_cpu(rsp->req_lim_delta)); 198762306a36Sopenharmony_ci 198862306a36Sopenharmony_ci scsi_done(scmnd); 198962306a36Sopenharmony_ci } 199062306a36Sopenharmony_ci} 199162306a36Sopenharmony_ci 199262306a36Sopenharmony_cistatic int srp_response_common(struct srp_rdma_ch *ch, s32 req_delta, 199362306a36Sopenharmony_ci void *rsp, int len) 199462306a36Sopenharmony_ci{ 199562306a36Sopenharmony_ci struct srp_target_port *target = ch->target; 199662306a36Sopenharmony_ci struct ib_device *dev = target->srp_host->srp_dev->dev; 199762306a36Sopenharmony_ci unsigned long flags; 199862306a36Sopenharmony_ci struct srp_iu *iu; 199962306a36Sopenharmony_ci int err; 200062306a36Sopenharmony_ci 200162306a36Sopenharmony_ci spin_lock_irqsave(&ch->lock, flags); 200262306a36Sopenharmony_ci ch->req_lim += req_delta; 200362306a36Sopenharmony_ci iu = __srp_get_tx_iu(ch, SRP_IU_RSP); 200462306a36Sopenharmony_ci spin_unlock_irqrestore(&ch->lock, flags); 200562306a36Sopenharmony_ci 200662306a36Sopenharmony_ci if (!iu) { 200762306a36Sopenharmony_ci shost_printk(KERN_ERR, target->scsi_host, PFX 200862306a36Sopenharmony_ci "no IU available to send response\n"); 200962306a36Sopenharmony_ci return 1; 201062306a36Sopenharmony_ci } 201162306a36Sopenharmony_ci 201262306a36Sopenharmony_ci iu->num_sge = 1; 201362306a36Sopenharmony_ci ib_dma_sync_single_for_cpu(dev, iu->dma, len, DMA_TO_DEVICE); 201462306a36Sopenharmony_ci memcpy(iu->buf, rsp, len); 201562306a36Sopenharmony_ci ib_dma_sync_single_for_device(dev, iu->dma, len, DMA_TO_DEVICE); 201662306a36Sopenharmony_ci 201762306a36Sopenharmony_ci err = srp_post_send(ch, iu, len); 201862306a36Sopenharmony_ci if (err) { 201962306a36Sopenharmony_ci shost_printk(KERN_ERR, target->scsi_host, PFX 202062306a36Sopenharmony_ci "unable to post response: %d\n", err); 202162306a36Sopenharmony_ci srp_put_tx_iu(ch, iu, SRP_IU_RSP); 202262306a36Sopenharmony_ci } 202362306a36Sopenharmony_ci 202462306a36Sopenharmony_ci return err; 202562306a36Sopenharmony_ci} 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_cistatic void srp_process_cred_req(struct srp_rdma_ch *ch, 202862306a36Sopenharmony_ci struct srp_cred_req *req) 202962306a36Sopenharmony_ci{ 203062306a36Sopenharmony_ci struct srp_cred_rsp rsp = { 203162306a36Sopenharmony_ci .opcode = SRP_CRED_RSP, 203262306a36Sopenharmony_ci .tag = req->tag, 203362306a36Sopenharmony_ci }; 203462306a36Sopenharmony_ci s32 delta = be32_to_cpu(req->req_lim_delta); 203562306a36Sopenharmony_ci 203662306a36Sopenharmony_ci if (srp_response_common(ch, delta, &rsp, sizeof(rsp))) 203762306a36Sopenharmony_ci shost_printk(KERN_ERR, ch->target->scsi_host, PFX 203862306a36Sopenharmony_ci "problems processing SRP_CRED_REQ\n"); 203962306a36Sopenharmony_ci} 204062306a36Sopenharmony_ci 204162306a36Sopenharmony_cistatic void srp_process_aer_req(struct srp_rdma_ch *ch, 204262306a36Sopenharmony_ci struct srp_aer_req *req) 204362306a36Sopenharmony_ci{ 204462306a36Sopenharmony_ci struct srp_target_port *target = ch->target; 204562306a36Sopenharmony_ci struct srp_aer_rsp rsp = { 204662306a36Sopenharmony_ci .opcode = SRP_AER_RSP, 204762306a36Sopenharmony_ci .tag = req->tag, 204862306a36Sopenharmony_ci }; 204962306a36Sopenharmony_ci s32 delta = be32_to_cpu(req->req_lim_delta); 205062306a36Sopenharmony_ci 205162306a36Sopenharmony_ci shost_printk(KERN_ERR, target->scsi_host, PFX 205262306a36Sopenharmony_ci "ignoring AER for LUN %llu\n", scsilun_to_int(&req->lun)); 205362306a36Sopenharmony_ci 205462306a36Sopenharmony_ci if (srp_response_common(ch, delta, &rsp, sizeof(rsp))) 205562306a36Sopenharmony_ci shost_printk(KERN_ERR, target->scsi_host, PFX 205662306a36Sopenharmony_ci "problems processing SRP_AER_REQ\n"); 205762306a36Sopenharmony_ci} 205862306a36Sopenharmony_ci 205962306a36Sopenharmony_cistatic void srp_recv_done(struct ib_cq *cq, struct ib_wc *wc) 206062306a36Sopenharmony_ci{ 206162306a36Sopenharmony_ci struct srp_iu *iu = container_of(wc->wr_cqe, struct srp_iu, cqe); 206262306a36Sopenharmony_ci struct srp_rdma_ch *ch = cq->cq_context; 206362306a36Sopenharmony_ci struct srp_target_port *target = ch->target; 206462306a36Sopenharmony_ci struct ib_device *dev = target->srp_host->srp_dev->dev; 206562306a36Sopenharmony_ci int res; 206662306a36Sopenharmony_ci u8 opcode; 206762306a36Sopenharmony_ci 206862306a36Sopenharmony_ci if (unlikely(wc->status != IB_WC_SUCCESS)) { 206962306a36Sopenharmony_ci srp_handle_qp_err(cq, wc, "RECV"); 207062306a36Sopenharmony_ci return; 207162306a36Sopenharmony_ci } 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ci ib_dma_sync_single_for_cpu(dev, iu->dma, ch->max_ti_iu_len, 207462306a36Sopenharmony_ci DMA_FROM_DEVICE); 207562306a36Sopenharmony_ci 207662306a36Sopenharmony_ci opcode = *(u8 *) iu->buf; 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_ci if (0) { 207962306a36Sopenharmony_ci shost_printk(KERN_ERR, target->scsi_host, 208062306a36Sopenharmony_ci PFX "recv completion, opcode 0x%02x\n", opcode); 208162306a36Sopenharmony_ci print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 8, 1, 208262306a36Sopenharmony_ci iu->buf, wc->byte_len, true); 208362306a36Sopenharmony_ci } 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ci switch (opcode) { 208662306a36Sopenharmony_ci case SRP_RSP: 208762306a36Sopenharmony_ci srp_process_rsp(ch, iu->buf); 208862306a36Sopenharmony_ci break; 208962306a36Sopenharmony_ci 209062306a36Sopenharmony_ci case SRP_CRED_REQ: 209162306a36Sopenharmony_ci srp_process_cred_req(ch, iu->buf); 209262306a36Sopenharmony_ci break; 209362306a36Sopenharmony_ci 209462306a36Sopenharmony_ci case SRP_AER_REQ: 209562306a36Sopenharmony_ci srp_process_aer_req(ch, iu->buf); 209662306a36Sopenharmony_ci break; 209762306a36Sopenharmony_ci 209862306a36Sopenharmony_ci case SRP_T_LOGOUT: 209962306a36Sopenharmony_ci /* XXX Handle target logout */ 210062306a36Sopenharmony_ci shost_printk(KERN_WARNING, target->scsi_host, 210162306a36Sopenharmony_ci PFX "Got target logout request\n"); 210262306a36Sopenharmony_ci break; 210362306a36Sopenharmony_ci 210462306a36Sopenharmony_ci default: 210562306a36Sopenharmony_ci shost_printk(KERN_WARNING, target->scsi_host, 210662306a36Sopenharmony_ci PFX "Unhandled SRP opcode 0x%02x\n", opcode); 210762306a36Sopenharmony_ci break; 210862306a36Sopenharmony_ci } 210962306a36Sopenharmony_ci 211062306a36Sopenharmony_ci ib_dma_sync_single_for_device(dev, iu->dma, ch->max_ti_iu_len, 211162306a36Sopenharmony_ci DMA_FROM_DEVICE); 211262306a36Sopenharmony_ci 211362306a36Sopenharmony_ci res = srp_post_recv(ch, iu); 211462306a36Sopenharmony_ci if (res != 0) 211562306a36Sopenharmony_ci shost_printk(KERN_ERR, target->scsi_host, 211662306a36Sopenharmony_ci PFX "Recv failed with error code %d\n", res); 211762306a36Sopenharmony_ci} 211862306a36Sopenharmony_ci 211962306a36Sopenharmony_ci/** 212062306a36Sopenharmony_ci * srp_tl_err_work() - handle a transport layer error 212162306a36Sopenharmony_ci * @work: Work structure embedded in an SRP target port. 212262306a36Sopenharmony_ci * 212362306a36Sopenharmony_ci * Note: This function may get invoked before the rport has been created, 212462306a36Sopenharmony_ci * hence the target->rport test. 212562306a36Sopenharmony_ci */ 212662306a36Sopenharmony_cistatic void srp_tl_err_work(struct work_struct *work) 212762306a36Sopenharmony_ci{ 212862306a36Sopenharmony_ci struct srp_target_port *target; 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_ci target = container_of(work, struct srp_target_port, tl_err_work); 213162306a36Sopenharmony_ci if (target->rport) 213262306a36Sopenharmony_ci srp_start_tl_fail_timers(target->rport); 213362306a36Sopenharmony_ci} 213462306a36Sopenharmony_ci 213562306a36Sopenharmony_cistatic void srp_handle_qp_err(struct ib_cq *cq, struct ib_wc *wc, 213662306a36Sopenharmony_ci const char *opname) 213762306a36Sopenharmony_ci{ 213862306a36Sopenharmony_ci struct srp_rdma_ch *ch = cq->cq_context; 213962306a36Sopenharmony_ci struct srp_target_port *target = ch->target; 214062306a36Sopenharmony_ci 214162306a36Sopenharmony_ci if (ch->connected && !target->qp_in_error) { 214262306a36Sopenharmony_ci shost_printk(KERN_ERR, target->scsi_host, 214362306a36Sopenharmony_ci PFX "failed %s status %s (%d) for CQE %p\n", 214462306a36Sopenharmony_ci opname, ib_wc_status_msg(wc->status), wc->status, 214562306a36Sopenharmony_ci wc->wr_cqe); 214662306a36Sopenharmony_ci queue_work(system_long_wq, &target->tl_err_work); 214762306a36Sopenharmony_ci } 214862306a36Sopenharmony_ci target->qp_in_error = true; 214962306a36Sopenharmony_ci} 215062306a36Sopenharmony_ci 215162306a36Sopenharmony_cistatic int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd) 215262306a36Sopenharmony_ci{ 215362306a36Sopenharmony_ci struct request *rq = scsi_cmd_to_rq(scmnd); 215462306a36Sopenharmony_ci struct srp_target_port *target = host_to_target(shost); 215562306a36Sopenharmony_ci struct srp_rdma_ch *ch; 215662306a36Sopenharmony_ci struct srp_request *req = scsi_cmd_priv(scmnd); 215762306a36Sopenharmony_ci struct srp_iu *iu; 215862306a36Sopenharmony_ci struct srp_cmd *cmd; 215962306a36Sopenharmony_ci struct ib_device *dev; 216062306a36Sopenharmony_ci unsigned long flags; 216162306a36Sopenharmony_ci u32 tag; 216262306a36Sopenharmony_ci int len, ret; 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_ci scmnd->result = srp_chkready(target->rport); 216562306a36Sopenharmony_ci if (unlikely(scmnd->result)) 216662306a36Sopenharmony_ci goto err; 216762306a36Sopenharmony_ci 216862306a36Sopenharmony_ci WARN_ON_ONCE(rq->tag < 0); 216962306a36Sopenharmony_ci tag = blk_mq_unique_tag(rq); 217062306a36Sopenharmony_ci ch = &target->ch[blk_mq_unique_tag_to_hwq(tag)]; 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_ci spin_lock_irqsave(&ch->lock, flags); 217362306a36Sopenharmony_ci iu = __srp_get_tx_iu(ch, SRP_IU_CMD); 217462306a36Sopenharmony_ci spin_unlock_irqrestore(&ch->lock, flags); 217562306a36Sopenharmony_ci 217662306a36Sopenharmony_ci if (!iu) 217762306a36Sopenharmony_ci goto err; 217862306a36Sopenharmony_ci 217962306a36Sopenharmony_ci dev = target->srp_host->srp_dev->dev; 218062306a36Sopenharmony_ci ib_dma_sync_single_for_cpu(dev, iu->dma, ch->max_it_iu_len, 218162306a36Sopenharmony_ci DMA_TO_DEVICE); 218262306a36Sopenharmony_ci 218362306a36Sopenharmony_ci cmd = iu->buf; 218462306a36Sopenharmony_ci memset(cmd, 0, sizeof *cmd); 218562306a36Sopenharmony_ci 218662306a36Sopenharmony_ci cmd->opcode = SRP_CMD; 218762306a36Sopenharmony_ci int_to_scsilun(scmnd->device->lun, &cmd->lun); 218862306a36Sopenharmony_ci cmd->tag = tag; 218962306a36Sopenharmony_ci memcpy(cmd->cdb, scmnd->cmnd, scmnd->cmd_len); 219062306a36Sopenharmony_ci if (unlikely(scmnd->cmd_len > sizeof(cmd->cdb))) { 219162306a36Sopenharmony_ci cmd->add_cdb_len = round_up(scmnd->cmd_len - sizeof(cmd->cdb), 219262306a36Sopenharmony_ci 4); 219362306a36Sopenharmony_ci if (WARN_ON_ONCE(cmd->add_cdb_len > SRP_MAX_ADD_CDB_LEN)) 219462306a36Sopenharmony_ci goto err_iu; 219562306a36Sopenharmony_ci } 219662306a36Sopenharmony_ci 219762306a36Sopenharmony_ci req->scmnd = scmnd; 219862306a36Sopenharmony_ci req->cmd = iu; 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_ci len = srp_map_data(scmnd, ch, req); 220162306a36Sopenharmony_ci if (len < 0) { 220262306a36Sopenharmony_ci shost_printk(KERN_ERR, target->scsi_host, 220362306a36Sopenharmony_ci PFX "Failed to map data (%d)\n", len); 220462306a36Sopenharmony_ci /* 220562306a36Sopenharmony_ci * If we ran out of memory descriptors (-ENOMEM) because an 220662306a36Sopenharmony_ci * application is queuing many requests with more than 220762306a36Sopenharmony_ci * max_pages_per_mr sg-list elements, tell the SCSI mid-layer 220862306a36Sopenharmony_ci * to reduce queue depth temporarily. 220962306a36Sopenharmony_ci */ 221062306a36Sopenharmony_ci scmnd->result = len == -ENOMEM ? 221162306a36Sopenharmony_ci DID_OK << 16 | SAM_STAT_TASK_SET_FULL : DID_ERROR << 16; 221262306a36Sopenharmony_ci goto err_iu; 221362306a36Sopenharmony_ci } 221462306a36Sopenharmony_ci 221562306a36Sopenharmony_ci ib_dma_sync_single_for_device(dev, iu->dma, ch->max_it_iu_len, 221662306a36Sopenharmony_ci DMA_TO_DEVICE); 221762306a36Sopenharmony_ci 221862306a36Sopenharmony_ci if (srp_post_send(ch, iu, len)) { 221962306a36Sopenharmony_ci shost_printk(KERN_ERR, target->scsi_host, PFX "Send failed\n"); 222062306a36Sopenharmony_ci scmnd->result = DID_ERROR << 16; 222162306a36Sopenharmony_ci goto err_unmap; 222262306a36Sopenharmony_ci } 222362306a36Sopenharmony_ci 222462306a36Sopenharmony_ci return 0; 222562306a36Sopenharmony_ci 222662306a36Sopenharmony_cierr_unmap: 222762306a36Sopenharmony_ci srp_unmap_data(scmnd, ch, req); 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_cierr_iu: 223062306a36Sopenharmony_ci srp_put_tx_iu(ch, iu, SRP_IU_CMD); 223162306a36Sopenharmony_ci 223262306a36Sopenharmony_ci /* 223362306a36Sopenharmony_ci * Avoid that the loops that iterate over the request ring can 223462306a36Sopenharmony_ci * encounter a dangling SCSI command pointer. 223562306a36Sopenharmony_ci */ 223662306a36Sopenharmony_ci req->scmnd = NULL; 223762306a36Sopenharmony_ci 223862306a36Sopenharmony_cierr: 223962306a36Sopenharmony_ci if (scmnd->result) { 224062306a36Sopenharmony_ci scsi_done(scmnd); 224162306a36Sopenharmony_ci ret = 0; 224262306a36Sopenharmony_ci } else { 224362306a36Sopenharmony_ci ret = SCSI_MLQUEUE_HOST_BUSY; 224462306a36Sopenharmony_ci } 224562306a36Sopenharmony_ci 224662306a36Sopenharmony_ci return ret; 224762306a36Sopenharmony_ci} 224862306a36Sopenharmony_ci 224962306a36Sopenharmony_ci/* 225062306a36Sopenharmony_ci * Note: the resources allocated in this function are freed in 225162306a36Sopenharmony_ci * srp_free_ch_ib(). 225262306a36Sopenharmony_ci */ 225362306a36Sopenharmony_cistatic int srp_alloc_iu_bufs(struct srp_rdma_ch *ch) 225462306a36Sopenharmony_ci{ 225562306a36Sopenharmony_ci struct srp_target_port *target = ch->target; 225662306a36Sopenharmony_ci int i; 225762306a36Sopenharmony_ci 225862306a36Sopenharmony_ci ch->rx_ring = kcalloc(target->queue_size, sizeof(*ch->rx_ring), 225962306a36Sopenharmony_ci GFP_KERNEL); 226062306a36Sopenharmony_ci if (!ch->rx_ring) 226162306a36Sopenharmony_ci goto err_no_ring; 226262306a36Sopenharmony_ci ch->tx_ring = kcalloc(target->queue_size, sizeof(*ch->tx_ring), 226362306a36Sopenharmony_ci GFP_KERNEL); 226462306a36Sopenharmony_ci if (!ch->tx_ring) 226562306a36Sopenharmony_ci goto err_no_ring; 226662306a36Sopenharmony_ci 226762306a36Sopenharmony_ci for (i = 0; i < target->queue_size; ++i) { 226862306a36Sopenharmony_ci ch->rx_ring[i] = srp_alloc_iu(target->srp_host, 226962306a36Sopenharmony_ci ch->max_ti_iu_len, 227062306a36Sopenharmony_ci GFP_KERNEL, DMA_FROM_DEVICE); 227162306a36Sopenharmony_ci if (!ch->rx_ring[i]) 227262306a36Sopenharmony_ci goto err; 227362306a36Sopenharmony_ci } 227462306a36Sopenharmony_ci 227562306a36Sopenharmony_ci for (i = 0; i < target->queue_size; ++i) { 227662306a36Sopenharmony_ci ch->tx_ring[i] = srp_alloc_iu(target->srp_host, 227762306a36Sopenharmony_ci ch->max_it_iu_len, 227862306a36Sopenharmony_ci GFP_KERNEL, DMA_TO_DEVICE); 227962306a36Sopenharmony_ci if (!ch->tx_ring[i]) 228062306a36Sopenharmony_ci goto err; 228162306a36Sopenharmony_ci 228262306a36Sopenharmony_ci list_add(&ch->tx_ring[i]->list, &ch->free_tx); 228362306a36Sopenharmony_ci } 228462306a36Sopenharmony_ci 228562306a36Sopenharmony_ci return 0; 228662306a36Sopenharmony_ci 228762306a36Sopenharmony_cierr: 228862306a36Sopenharmony_ci for (i = 0; i < target->queue_size; ++i) { 228962306a36Sopenharmony_ci srp_free_iu(target->srp_host, ch->rx_ring[i]); 229062306a36Sopenharmony_ci srp_free_iu(target->srp_host, ch->tx_ring[i]); 229162306a36Sopenharmony_ci } 229262306a36Sopenharmony_ci 229362306a36Sopenharmony_ci 229462306a36Sopenharmony_cierr_no_ring: 229562306a36Sopenharmony_ci kfree(ch->tx_ring); 229662306a36Sopenharmony_ci ch->tx_ring = NULL; 229762306a36Sopenharmony_ci kfree(ch->rx_ring); 229862306a36Sopenharmony_ci ch->rx_ring = NULL; 229962306a36Sopenharmony_ci 230062306a36Sopenharmony_ci return -ENOMEM; 230162306a36Sopenharmony_ci} 230262306a36Sopenharmony_ci 230362306a36Sopenharmony_cistatic uint32_t srp_compute_rq_tmo(struct ib_qp_attr *qp_attr, int attr_mask) 230462306a36Sopenharmony_ci{ 230562306a36Sopenharmony_ci uint64_t T_tr_ns, max_compl_time_ms; 230662306a36Sopenharmony_ci uint32_t rq_tmo_jiffies; 230762306a36Sopenharmony_ci 230862306a36Sopenharmony_ci /* 230962306a36Sopenharmony_ci * According to section 11.2.4.2 in the IBTA spec (Modify Queue Pair, 231062306a36Sopenharmony_ci * table 91), both the QP timeout and the retry count have to be set 231162306a36Sopenharmony_ci * for RC QP's during the RTR to RTS transition. 231262306a36Sopenharmony_ci */ 231362306a36Sopenharmony_ci WARN_ON_ONCE((attr_mask & (IB_QP_TIMEOUT | IB_QP_RETRY_CNT)) != 231462306a36Sopenharmony_ci (IB_QP_TIMEOUT | IB_QP_RETRY_CNT)); 231562306a36Sopenharmony_ci 231662306a36Sopenharmony_ci /* 231762306a36Sopenharmony_ci * Set target->rq_tmo_jiffies to one second more than the largest time 231862306a36Sopenharmony_ci * it can take before an error completion is generated. See also 231962306a36Sopenharmony_ci * C9-140..142 in the IBTA spec for more information about how to 232062306a36Sopenharmony_ci * convert the QP Local ACK Timeout value to nanoseconds. 232162306a36Sopenharmony_ci */ 232262306a36Sopenharmony_ci T_tr_ns = 4096 * (1ULL << qp_attr->timeout); 232362306a36Sopenharmony_ci max_compl_time_ms = qp_attr->retry_cnt * 4 * T_tr_ns; 232462306a36Sopenharmony_ci do_div(max_compl_time_ms, NSEC_PER_MSEC); 232562306a36Sopenharmony_ci rq_tmo_jiffies = msecs_to_jiffies(max_compl_time_ms + 1000); 232662306a36Sopenharmony_ci 232762306a36Sopenharmony_ci return rq_tmo_jiffies; 232862306a36Sopenharmony_ci} 232962306a36Sopenharmony_ci 233062306a36Sopenharmony_cistatic void srp_cm_rep_handler(struct ib_cm_id *cm_id, 233162306a36Sopenharmony_ci const struct srp_login_rsp *lrsp, 233262306a36Sopenharmony_ci struct srp_rdma_ch *ch) 233362306a36Sopenharmony_ci{ 233462306a36Sopenharmony_ci struct srp_target_port *target = ch->target; 233562306a36Sopenharmony_ci struct ib_qp_attr *qp_attr = NULL; 233662306a36Sopenharmony_ci int attr_mask = 0; 233762306a36Sopenharmony_ci int ret = 0; 233862306a36Sopenharmony_ci int i; 233962306a36Sopenharmony_ci 234062306a36Sopenharmony_ci if (lrsp->opcode == SRP_LOGIN_RSP) { 234162306a36Sopenharmony_ci ch->max_ti_iu_len = be32_to_cpu(lrsp->max_ti_iu_len); 234262306a36Sopenharmony_ci ch->req_lim = be32_to_cpu(lrsp->req_lim_delta); 234362306a36Sopenharmony_ci ch->use_imm_data = srp_use_imm_data && 234462306a36Sopenharmony_ci (lrsp->rsp_flags & SRP_LOGIN_RSP_IMMED_SUPP); 234562306a36Sopenharmony_ci ch->max_it_iu_len = srp_max_it_iu_len(target->cmd_sg_cnt, 234662306a36Sopenharmony_ci ch->use_imm_data, 234762306a36Sopenharmony_ci target->max_it_iu_size); 234862306a36Sopenharmony_ci WARN_ON_ONCE(ch->max_it_iu_len > 234962306a36Sopenharmony_ci be32_to_cpu(lrsp->max_it_iu_len)); 235062306a36Sopenharmony_ci 235162306a36Sopenharmony_ci if (ch->use_imm_data) 235262306a36Sopenharmony_ci shost_printk(KERN_DEBUG, target->scsi_host, 235362306a36Sopenharmony_ci PFX "using immediate data\n"); 235462306a36Sopenharmony_ci 235562306a36Sopenharmony_ci /* 235662306a36Sopenharmony_ci * Reserve credits for task management so we don't 235762306a36Sopenharmony_ci * bounce requests back to the SCSI mid-layer. 235862306a36Sopenharmony_ci */ 235962306a36Sopenharmony_ci target->scsi_host->can_queue 236062306a36Sopenharmony_ci = min(ch->req_lim - SRP_TSK_MGMT_SQ_SIZE, 236162306a36Sopenharmony_ci target->scsi_host->can_queue); 236262306a36Sopenharmony_ci target->scsi_host->cmd_per_lun 236362306a36Sopenharmony_ci = min_t(int, target->scsi_host->can_queue, 236462306a36Sopenharmony_ci target->scsi_host->cmd_per_lun); 236562306a36Sopenharmony_ci } else { 236662306a36Sopenharmony_ci shost_printk(KERN_WARNING, target->scsi_host, 236762306a36Sopenharmony_ci PFX "Unhandled RSP opcode %#x\n", lrsp->opcode); 236862306a36Sopenharmony_ci ret = -ECONNRESET; 236962306a36Sopenharmony_ci goto error; 237062306a36Sopenharmony_ci } 237162306a36Sopenharmony_ci 237262306a36Sopenharmony_ci if (!ch->rx_ring) { 237362306a36Sopenharmony_ci ret = srp_alloc_iu_bufs(ch); 237462306a36Sopenharmony_ci if (ret) 237562306a36Sopenharmony_ci goto error; 237662306a36Sopenharmony_ci } 237762306a36Sopenharmony_ci 237862306a36Sopenharmony_ci for (i = 0; i < target->queue_size; i++) { 237962306a36Sopenharmony_ci struct srp_iu *iu = ch->rx_ring[i]; 238062306a36Sopenharmony_ci 238162306a36Sopenharmony_ci ret = srp_post_recv(ch, iu); 238262306a36Sopenharmony_ci if (ret) 238362306a36Sopenharmony_ci goto error; 238462306a36Sopenharmony_ci } 238562306a36Sopenharmony_ci 238662306a36Sopenharmony_ci if (!target->using_rdma_cm) { 238762306a36Sopenharmony_ci ret = -ENOMEM; 238862306a36Sopenharmony_ci qp_attr = kmalloc(sizeof(*qp_attr), GFP_KERNEL); 238962306a36Sopenharmony_ci if (!qp_attr) 239062306a36Sopenharmony_ci goto error; 239162306a36Sopenharmony_ci 239262306a36Sopenharmony_ci qp_attr->qp_state = IB_QPS_RTR; 239362306a36Sopenharmony_ci ret = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask); 239462306a36Sopenharmony_ci if (ret) 239562306a36Sopenharmony_ci goto error_free; 239662306a36Sopenharmony_ci 239762306a36Sopenharmony_ci ret = ib_modify_qp(ch->qp, qp_attr, attr_mask); 239862306a36Sopenharmony_ci if (ret) 239962306a36Sopenharmony_ci goto error_free; 240062306a36Sopenharmony_ci 240162306a36Sopenharmony_ci qp_attr->qp_state = IB_QPS_RTS; 240262306a36Sopenharmony_ci ret = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask); 240362306a36Sopenharmony_ci if (ret) 240462306a36Sopenharmony_ci goto error_free; 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_ci target->rq_tmo_jiffies = srp_compute_rq_tmo(qp_attr, attr_mask); 240762306a36Sopenharmony_ci 240862306a36Sopenharmony_ci ret = ib_modify_qp(ch->qp, qp_attr, attr_mask); 240962306a36Sopenharmony_ci if (ret) 241062306a36Sopenharmony_ci goto error_free; 241162306a36Sopenharmony_ci 241262306a36Sopenharmony_ci ret = ib_send_cm_rtu(cm_id, NULL, 0); 241362306a36Sopenharmony_ci } 241462306a36Sopenharmony_ci 241562306a36Sopenharmony_cierror_free: 241662306a36Sopenharmony_ci kfree(qp_attr); 241762306a36Sopenharmony_ci 241862306a36Sopenharmony_cierror: 241962306a36Sopenharmony_ci ch->status = ret; 242062306a36Sopenharmony_ci} 242162306a36Sopenharmony_ci 242262306a36Sopenharmony_cistatic void srp_ib_cm_rej_handler(struct ib_cm_id *cm_id, 242362306a36Sopenharmony_ci const struct ib_cm_event *event, 242462306a36Sopenharmony_ci struct srp_rdma_ch *ch) 242562306a36Sopenharmony_ci{ 242662306a36Sopenharmony_ci struct srp_target_port *target = ch->target; 242762306a36Sopenharmony_ci struct Scsi_Host *shost = target->scsi_host; 242862306a36Sopenharmony_ci struct ib_class_port_info *cpi; 242962306a36Sopenharmony_ci int opcode; 243062306a36Sopenharmony_ci u16 dlid; 243162306a36Sopenharmony_ci 243262306a36Sopenharmony_ci switch (event->param.rej_rcvd.reason) { 243362306a36Sopenharmony_ci case IB_CM_REJ_PORT_CM_REDIRECT: 243462306a36Sopenharmony_ci cpi = event->param.rej_rcvd.ari; 243562306a36Sopenharmony_ci dlid = be16_to_cpu(cpi->redirect_lid); 243662306a36Sopenharmony_ci sa_path_set_dlid(&ch->ib_cm.path, dlid); 243762306a36Sopenharmony_ci ch->ib_cm.path.pkey = cpi->redirect_pkey; 243862306a36Sopenharmony_ci cm_id->remote_cm_qpn = be32_to_cpu(cpi->redirect_qp) & 0x00ffffff; 243962306a36Sopenharmony_ci memcpy(ch->ib_cm.path.dgid.raw, cpi->redirect_gid, 16); 244062306a36Sopenharmony_ci 244162306a36Sopenharmony_ci ch->status = dlid ? SRP_DLID_REDIRECT : SRP_PORT_REDIRECT; 244262306a36Sopenharmony_ci break; 244362306a36Sopenharmony_ci 244462306a36Sopenharmony_ci case IB_CM_REJ_PORT_REDIRECT: 244562306a36Sopenharmony_ci if (srp_target_is_topspin(target)) { 244662306a36Sopenharmony_ci union ib_gid *dgid = &ch->ib_cm.path.dgid; 244762306a36Sopenharmony_ci 244862306a36Sopenharmony_ci /* 244962306a36Sopenharmony_ci * Topspin/Cisco SRP gateways incorrectly send 245062306a36Sopenharmony_ci * reject reason code 25 when they mean 24 245162306a36Sopenharmony_ci * (port redirect). 245262306a36Sopenharmony_ci */ 245362306a36Sopenharmony_ci memcpy(dgid->raw, event->param.rej_rcvd.ari, 16); 245462306a36Sopenharmony_ci 245562306a36Sopenharmony_ci shost_printk(KERN_DEBUG, shost, 245662306a36Sopenharmony_ci PFX "Topspin/Cisco redirect to target port GID %016llx%016llx\n", 245762306a36Sopenharmony_ci be64_to_cpu(dgid->global.subnet_prefix), 245862306a36Sopenharmony_ci be64_to_cpu(dgid->global.interface_id)); 245962306a36Sopenharmony_ci 246062306a36Sopenharmony_ci ch->status = SRP_PORT_REDIRECT; 246162306a36Sopenharmony_ci } else { 246262306a36Sopenharmony_ci shost_printk(KERN_WARNING, shost, 246362306a36Sopenharmony_ci " REJ reason: IB_CM_REJ_PORT_REDIRECT\n"); 246462306a36Sopenharmony_ci ch->status = -ECONNRESET; 246562306a36Sopenharmony_ci } 246662306a36Sopenharmony_ci break; 246762306a36Sopenharmony_ci 246862306a36Sopenharmony_ci case IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID: 246962306a36Sopenharmony_ci shost_printk(KERN_WARNING, shost, 247062306a36Sopenharmony_ci " REJ reason: IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID\n"); 247162306a36Sopenharmony_ci ch->status = -ECONNRESET; 247262306a36Sopenharmony_ci break; 247362306a36Sopenharmony_ci 247462306a36Sopenharmony_ci case IB_CM_REJ_CONSUMER_DEFINED: 247562306a36Sopenharmony_ci opcode = *(u8 *) event->private_data; 247662306a36Sopenharmony_ci if (opcode == SRP_LOGIN_REJ) { 247762306a36Sopenharmony_ci struct srp_login_rej *rej = event->private_data; 247862306a36Sopenharmony_ci u32 reason = be32_to_cpu(rej->reason); 247962306a36Sopenharmony_ci 248062306a36Sopenharmony_ci if (reason == SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE) 248162306a36Sopenharmony_ci shost_printk(KERN_WARNING, shost, 248262306a36Sopenharmony_ci PFX "SRP_LOGIN_REJ: requested max_it_iu_len too large\n"); 248362306a36Sopenharmony_ci else 248462306a36Sopenharmony_ci shost_printk(KERN_WARNING, shost, PFX 248562306a36Sopenharmony_ci "SRP LOGIN from %pI6 to %pI6 REJECTED, reason 0x%08x\n", 248662306a36Sopenharmony_ci target->sgid.raw, 248762306a36Sopenharmony_ci target->ib_cm.orig_dgid.raw, 248862306a36Sopenharmony_ci reason); 248962306a36Sopenharmony_ci } else 249062306a36Sopenharmony_ci shost_printk(KERN_WARNING, shost, 249162306a36Sopenharmony_ci " REJ reason: IB_CM_REJ_CONSUMER_DEFINED," 249262306a36Sopenharmony_ci " opcode 0x%02x\n", opcode); 249362306a36Sopenharmony_ci ch->status = -ECONNRESET; 249462306a36Sopenharmony_ci break; 249562306a36Sopenharmony_ci 249662306a36Sopenharmony_ci case IB_CM_REJ_STALE_CONN: 249762306a36Sopenharmony_ci shost_printk(KERN_WARNING, shost, " REJ reason: stale connection\n"); 249862306a36Sopenharmony_ci ch->status = SRP_STALE_CONN; 249962306a36Sopenharmony_ci break; 250062306a36Sopenharmony_ci 250162306a36Sopenharmony_ci default: 250262306a36Sopenharmony_ci shost_printk(KERN_WARNING, shost, " REJ reason 0x%x\n", 250362306a36Sopenharmony_ci event->param.rej_rcvd.reason); 250462306a36Sopenharmony_ci ch->status = -ECONNRESET; 250562306a36Sopenharmony_ci } 250662306a36Sopenharmony_ci} 250762306a36Sopenharmony_ci 250862306a36Sopenharmony_cistatic int srp_ib_cm_handler(struct ib_cm_id *cm_id, 250962306a36Sopenharmony_ci const struct ib_cm_event *event) 251062306a36Sopenharmony_ci{ 251162306a36Sopenharmony_ci struct srp_rdma_ch *ch = cm_id->context; 251262306a36Sopenharmony_ci struct srp_target_port *target = ch->target; 251362306a36Sopenharmony_ci int comp = 0; 251462306a36Sopenharmony_ci 251562306a36Sopenharmony_ci switch (event->event) { 251662306a36Sopenharmony_ci case IB_CM_REQ_ERROR: 251762306a36Sopenharmony_ci shost_printk(KERN_DEBUG, target->scsi_host, 251862306a36Sopenharmony_ci PFX "Sending CM REQ failed\n"); 251962306a36Sopenharmony_ci comp = 1; 252062306a36Sopenharmony_ci ch->status = -ECONNRESET; 252162306a36Sopenharmony_ci break; 252262306a36Sopenharmony_ci 252362306a36Sopenharmony_ci case IB_CM_REP_RECEIVED: 252462306a36Sopenharmony_ci comp = 1; 252562306a36Sopenharmony_ci srp_cm_rep_handler(cm_id, event->private_data, ch); 252662306a36Sopenharmony_ci break; 252762306a36Sopenharmony_ci 252862306a36Sopenharmony_ci case IB_CM_REJ_RECEIVED: 252962306a36Sopenharmony_ci shost_printk(KERN_DEBUG, target->scsi_host, PFX "REJ received\n"); 253062306a36Sopenharmony_ci comp = 1; 253162306a36Sopenharmony_ci 253262306a36Sopenharmony_ci srp_ib_cm_rej_handler(cm_id, event, ch); 253362306a36Sopenharmony_ci break; 253462306a36Sopenharmony_ci 253562306a36Sopenharmony_ci case IB_CM_DREQ_RECEIVED: 253662306a36Sopenharmony_ci shost_printk(KERN_WARNING, target->scsi_host, 253762306a36Sopenharmony_ci PFX "DREQ received - connection closed\n"); 253862306a36Sopenharmony_ci ch->connected = false; 253962306a36Sopenharmony_ci if (ib_send_cm_drep(cm_id, NULL, 0)) 254062306a36Sopenharmony_ci shost_printk(KERN_ERR, target->scsi_host, 254162306a36Sopenharmony_ci PFX "Sending CM DREP failed\n"); 254262306a36Sopenharmony_ci queue_work(system_long_wq, &target->tl_err_work); 254362306a36Sopenharmony_ci break; 254462306a36Sopenharmony_ci 254562306a36Sopenharmony_ci case IB_CM_TIMEWAIT_EXIT: 254662306a36Sopenharmony_ci shost_printk(KERN_ERR, target->scsi_host, 254762306a36Sopenharmony_ci PFX "connection closed\n"); 254862306a36Sopenharmony_ci comp = 1; 254962306a36Sopenharmony_ci 255062306a36Sopenharmony_ci ch->status = 0; 255162306a36Sopenharmony_ci break; 255262306a36Sopenharmony_ci 255362306a36Sopenharmony_ci case IB_CM_MRA_RECEIVED: 255462306a36Sopenharmony_ci case IB_CM_DREQ_ERROR: 255562306a36Sopenharmony_ci case IB_CM_DREP_RECEIVED: 255662306a36Sopenharmony_ci break; 255762306a36Sopenharmony_ci 255862306a36Sopenharmony_ci default: 255962306a36Sopenharmony_ci shost_printk(KERN_WARNING, target->scsi_host, 256062306a36Sopenharmony_ci PFX "Unhandled CM event %d\n", event->event); 256162306a36Sopenharmony_ci break; 256262306a36Sopenharmony_ci } 256362306a36Sopenharmony_ci 256462306a36Sopenharmony_ci if (comp) 256562306a36Sopenharmony_ci complete(&ch->done); 256662306a36Sopenharmony_ci 256762306a36Sopenharmony_ci return 0; 256862306a36Sopenharmony_ci} 256962306a36Sopenharmony_ci 257062306a36Sopenharmony_cistatic void srp_rdma_cm_rej_handler(struct srp_rdma_ch *ch, 257162306a36Sopenharmony_ci struct rdma_cm_event *event) 257262306a36Sopenharmony_ci{ 257362306a36Sopenharmony_ci struct srp_target_port *target = ch->target; 257462306a36Sopenharmony_ci struct Scsi_Host *shost = target->scsi_host; 257562306a36Sopenharmony_ci int opcode; 257662306a36Sopenharmony_ci 257762306a36Sopenharmony_ci switch (event->status) { 257862306a36Sopenharmony_ci case IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID: 257962306a36Sopenharmony_ci shost_printk(KERN_WARNING, shost, 258062306a36Sopenharmony_ci " REJ reason: IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID\n"); 258162306a36Sopenharmony_ci ch->status = -ECONNRESET; 258262306a36Sopenharmony_ci break; 258362306a36Sopenharmony_ci 258462306a36Sopenharmony_ci case IB_CM_REJ_CONSUMER_DEFINED: 258562306a36Sopenharmony_ci opcode = *(u8 *) event->param.conn.private_data; 258662306a36Sopenharmony_ci if (opcode == SRP_LOGIN_REJ) { 258762306a36Sopenharmony_ci struct srp_login_rej *rej = 258862306a36Sopenharmony_ci (struct srp_login_rej *) 258962306a36Sopenharmony_ci event->param.conn.private_data; 259062306a36Sopenharmony_ci u32 reason = be32_to_cpu(rej->reason); 259162306a36Sopenharmony_ci 259262306a36Sopenharmony_ci if (reason == SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE) 259362306a36Sopenharmony_ci shost_printk(KERN_WARNING, shost, 259462306a36Sopenharmony_ci PFX "SRP_LOGIN_REJ: requested max_it_iu_len too large\n"); 259562306a36Sopenharmony_ci else 259662306a36Sopenharmony_ci shost_printk(KERN_WARNING, shost, 259762306a36Sopenharmony_ci PFX "SRP LOGIN REJECTED, reason 0x%08x\n", reason); 259862306a36Sopenharmony_ci } else { 259962306a36Sopenharmony_ci shost_printk(KERN_WARNING, shost, 260062306a36Sopenharmony_ci " REJ reason: IB_CM_REJ_CONSUMER_DEFINED, opcode 0x%02x\n", 260162306a36Sopenharmony_ci opcode); 260262306a36Sopenharmony_ci } 260362306a36Sopenharmony_ci ch->status = -ECONNRESET; 260462306a36Sopenharmony_ci break; 260562306a36Sopenharmony_ci 260662306a36Sopenharmony_ci case IB_CM_REJ_STALE_CONN: 260762306a36Sopenharmony_ci shost_printk(KERN_WARNING, shost, 260862306a36Sopenharmony_ci " REJ reason: stale connection\n"); 260962306a36Sopenharmony_ci ch->status = SRP_STALE_CONN; 261062306a36Sopenharmony_ci break; 261162306a36Sopenharmony_ci 261262306a36Sopenharmony_ci default: 261362306a36Sopenharmony_ci shost_printk(KERN_WARNING, shost, " REJ reason 0x%x\n", 261462306a36Sopenharmony_ci event->status); 261562306a36Sopenharmony_ci ch->status = -ECONNRESET; 261662306a36Sopenharmony_ci break; 261762306a36Sopenharmony_ci } 261862306a36Sopenharmony_ci} 261962306a36Sopenharmony_ci 262062306a36Sopenharmony_cistatic int srp_rdma_cm_handler(struct rdma_cm_id *cm_id, 262162306a36Sopenharmony_ci struct rdma_cm_event *event) 262262306a36Sopenharmony_ci{ 262362306a36Sopenharmony_ci struct srp_rdma_ch *ch = cm_id->context; 262462306a36Sopenharmony_ci struct srp_target_port *target = ch->target; 262562306a36Sopenharmony_ci int comp = 0; 262662306a36Sopenharmony_ci 262762306a36Sopenharmony_ci switch (event->event) { 262862306a36Sopenharmony_ci case RDMA_CM_EVENT_ADDR_RESOLVED: 262962306a36Sopenharmony_ci ch->status = 0; 263062306a36Sopenharmony_ci comp = 1; 263162306a36Sopenharmony_ci break; 263262306a36Sopenharmony_ci 263362306a36Sopenharmony_ci case RDMA_CM_EVENT_ADDR_ERROR: 263462306a36Sopenharmony_ci ch->status = -ENXIO; 263562306a36Sopenharmony_ci comp = 1; 263662306a36Sopenharmony_ci break; 263762306a36Sopenharmony_ci 263862306a36Sopenharmony_ci case RDMA_CM_EVENT_ROUTE_RESOLVED: 263962306a36Sopenharmony_ci ch->status = 0; 264062306a36Sopenharmony_ci comp = 1; 264162306a36Sopenharmony_ci break; 264262306a36Sopenharmony_ci 264362306a36Sopenharmony_ci case RDMA_CM_EVENT_ROUTE_ERROR: 264462306a36Sopenharmony_ci case RDMA_CM_EVENT_UNREACHABLE: 264562306a36Sopenharmony_ci ch->status = -EHOSTUNREACH; 264662306a36Sopenharmony_ci comp = 1; 264762306a36Sopenharmony_ci break; 264862306a36Sopenharmony_ci 264962306a36Sopenharmony_ci case RDMA_CM_EVENT_CONNECT_ERROR: 265062306a36Sopenharmony_ci shost_printk(KERN_DEBUG, target->scsi_host, 265162306a36Sopenharmony_ci PFX "Sending CM REQ failed\n"); 265262306a36Sopenharmony_ci comp = 1; 265362306a36Sopenharmony_ci ch->status = -ECONNRESET; 265462306a36Sopenharmony_ci break; 265562306a36Sopenharmony_ci 265662306a36Sopenharmony_ci case RDMA_CM_EVENT_ESTABLISHED: 265762306a36Sopenharmony_ci comp = 1; 265862306a36Sopenharmony_ci srp_cm_rep_handler(NULL, event->param.conn.private_data, ch); 265962306a36Sopenharmony_ci break; 266062306a36Sopenharmony_ci 266162306a36Sopenharmony_ci case RDMA_CM_EVENT_REJECTED: 266262306a36Sopenharmony_ci shost_printk(KERN_DEBUG, target->scsi_host, PFX "REJ received\n"); 266362306a36Sopenharmony_ci comp = 1; 266462306a36Sopenharmony_ci 266562306a36Sopenharmony_ci srp_rdma_cm_rej_handler(ch, event); 266662306a36Sopenharmony_ci break; 266762306a36Sopenharmony_ci 266862306a36Sopenharmony_ci case RDMA_CM_EVENT_DISCONNECTED: 266962306a36Sopenharmony_ci if (ch->connected) { 267062306a36Sopenharmony_ci shost_printk(KERN_WARNING, target->scsi_host, 267162306a36Sopenharmony_ci PFX "received DREQ\n"); 267262306a36Sopenharmony_ci rdma_disconnect(ch->rdma_cm.cm_id); 267362306a36Sopenharmony_ci comp = 1; 267462306a36Sopenharmony_ci ch->status = 0; 267562306a36Sopenharmony_ci queue_work(system_long_wq, &target->tl_err_work); 267662306a36Sopenharmony_ci } 267762306a36Sopenharmony_ci break; 267862306a36Sopenharmony_ci 267962306a36Sopenharmony_ci case RDMA_CM_EVENT_TIMEWAIT_EXIT: 268062306a36Sopenharmony_ci shost_printk(KERN_ERR, target->scsi_host, 268162306a36Sopenharmony_ci PFX "connection closed\n"); 268262306a36Sopenharmony_ci 268362306a36Sopenharmony_ci comp = 1; 268462306a36Sopenharmony_ci ch->status = 0; 268562306a36Sopenharmony_ci break; 268662306a36Sopenharmony_ci 268762306a36Sopenharmony_ci default: 268862306a36Sopenharmony_ci shost_printk(KERN_WARNING, target->scsi_host, 268962306a36Sopenharmony_ci PFX "Unhandled CM event %d\n", event->event); 269062306a36Sopenharmony_ci break; 269162306a36Sopenharmony_ci } 269262306a36Sopenharmony_ci 269362306a36Sopenharmony_ci if (comp) 269462306a36Sopenharmony_ci complete(&ch->done); 269562306a36Sopenharmony_ci 269662306a36Sopenharmony_ci return 0; 269762306a36Sopenharmony_ci} 269862306a36Sopenharmony_ci 269962306a36Sopenharmony_ci/** 270062306a36Sopenharmony_ci * srp_change_queue_depth - setting device queue depth 270162306a36Sopenharmony_ci * @sdev: scsi device struct 270262306a36Sopenharmony_ci * @qdepth: requested queue depth 270362306a36Sopenharmony_ci * 270462306a36Sopenharmony_ci * Returns queue depth. 270562306a36Sopenharmony_ci */ 270662306a36Sopenharmony_cistatic int 270762306a36Sopenharmony_cisrp_change_queue_depth(struct scsi_device *sdev, int qdepth) 270862306a36Sopenharmony_ci{ 270962306a36Sopenharmony_ci if (!sdev->tagged_supported) 271062306a36Sopenharmony_ci qdepth = 1; 271162306a36Sopenharmony_ci return scsi_change_queue_depth(sdev, qdepth); 271262306a36Sopenharmony_ci} 271362306a36Sopenharmony_ci 271462306a36Sopenharmony_cistatic int srp_send_tsk_mgmt(struct srp_rdma_ch *ch, u64 req_tag, u64 lun, 271562306a36Sopenharmony_ci u8 func, u8 *status) 271662306a36Sopenharmony_ci{ 271762306a36Sopenharmony_ci struct srp_target_port *target = ch->target; 271862306a36Sopenharmony_ci struct srp_rport *rport = target->rport; 271962306a36Sopenharmony_ci struct ib_device *dev = target->srp_host->srp_dev->dev; 272062306a36Sopenharmony_ci struct srp_iu *iu; 272162306a36Sopenharmony_ci struct srp_tsk_mgmt *tsk_mgmt; 272262306a36Sopenharmony_ci int res; 272362306a36Sopenharmony_ci 272462306a36Sopenharmony_ci if (!ch->connected || target->qp_in_error) 272562306a36Sopenharmony_ci return -1; 272662306a36Sopenharmony_ci 272762306a36Sopenharmony_ci /* 272862306a36Sopenharmony_ci * Lock the rport mutex to avoid that srp_create_ch_ib() is 272962306a36Sopenharmony_ci * invoked while a task management function is being sent. 273062306a36Sopenharmony_ci */ 273162306a36Sopenharmony_ci mutex_lock(&rport->mutex); 273262306a36Sopenharmony_ci spin_lock_irq(&ch->lock); 273362306a36Sopenharmony_ci iu = __srp_get_tx_iu(ch, SRP_IU_TSK_MGMT); 273462306a36Sopenharmony_ci spin_unlock_irq(&ch->lock); 273562306a36Sopenharmony_ci 273662306a36Sopenharmony_ci if (!iu) { 273762306a36Sopenharmony_ci mutex_unlock(&rport->mutex); 273862306a36Sopenharmony_ci 273962306a36Sopenharmony_ci return -1; 274062306a36Sopenharmony_ci } 274162306a36Sopenharmony_ci 274262306a36Sopenharmony_ci iu->num_sge = 1; 274362306a36Sopenharmony_ci 274462306a36Sopenharmony_ci ib_dma_sync_single_for_cpu(dev, iu->dma, sizeof *tsk_mgmt, 274562306a36Sopenharmony_ci DMA_TO_DEVICE); 274662306a36Sopenharmony_ci tsk_mgmt = iu->buf; 274762306a36Sopenharmony_ci memset(tsk_mgmt, 0, sizeof *tsk_mgmt); 274862306a36Sopenharmony_ci 274962306a36Sopenharmony_ci tsk_mgmt->opcode = SRP_TSK_MGMT; 275062306a36Sopenharmony_ci int_to_scsilun(lun, &tsk_mgmt->lun); 275162306a36Sopenharmony_ci tsk_mgmt->tsk_mgmt_func = func; 275262306a36Sopenharmony_ci tsk_mgmt->task_tag = req_tag; 275362306a36Sopenharmony_ci 275462306a36Sopenharmony_ci spin_lock_irq(&ch->lock); 275562306a36Sopenharmony_ci ch->tsk_mgmt_tag = (ch->tsk_mgmt_tag + 1) | SRP_TAG_TSK_MGMT; 275662306a36Sopenharmony_ci tsk_mgmt->tag = ch->tsk_mgmt_tag; 275762306a36Sopenharmony_ci spin_unlock_irq(&ch->lock); 275862306a36Sopenharmony_ci 275962306a36Sopenharmony_ci init_completion(&ch->tsk_mgmt_done); 276062306a36Sopenharmony_ci 276162306a36Sopenharmony_ci ib_dma_sync_single_for_device(dev, iu->dma, sizeof *tsk_mgmt, 276262306a36Sopenharmony_ci DMA_TO_DEVICE); 276362306a36Sopenharmony_ci if (srp_post_send(ch, iu, sizeof(*tsk_mgmt))) { 276462306a36Sopenharmony_ci srp_put_tx_iu(ch, iu, SRP_IU_TSK_MGMT); 276562306a36Sopenharmony_ci mutex_unlock(&rport->mutex); 276662306a36Sopenharmony_ci 276762306a36Sopenharmony_ci return -1; 276862306a36Sopenharmony_ci } 276962306a36Sopenharmony_ci res = wait_for_completion_timeout(&ch->tsk_mgmt_done, 277062306a36Sopenharmony_ci msecs_to_jiffies(SRP_ABORT_TIMEOUT_MS)); 277162306a36Sopenharmony_ci if (res > 0 && status) 277262306a36Sopenharmony_ci *status = ch->tsk_mgmt_status; 277362306a36Sopenharmony_ci mutex_unlock(&rport->mutex); 277462306a36Sopenharmony_ci 277562306a36Sopenharmony_ci WARN_ON_ONCE(res < 0); 277662306a36Sopenharmony_ci 277762306a36Sopenharmony_ci return res > 0 ? 0 : -1; 277862306a36Sopenharmony_ci} 277962306a36Sopenharmony_ci 278062306a36Sopenharmony_cistatic int srp_abort(struct scsi_cmnd *scmnd) 278162306a36Sopenharmony_ci{ 278262306a36Sopenharmony_ci struct srp_target_port *target = host_to_target(scmnd->device->host); 278362306a36Sopenharmony_ci struct srp_request *req = scsi_cmd_priv(scmnd); 278462306a36Sopenharmony_ci u32 tag; 278562306a36Sopenharmony_ci u16 ch_idx; 278662306a36Sopenharmony_ci struct srp_rdma_ch *ch; 278762306a36Sopenharmony_ci 278862306a36Sopenharmony_ci shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n"); 278962306a36Sopenharmony_ci 279062306a36Sopenharmony_ci tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmnd)); 279162306a36Sopenharmony_ci ch_idx = blk_mq_unique_tag_to_hwq(tag); 279262306a36Sopenharmony_ci if (WARN_ON_ONCE(ch_idx >= target->ch_count)) 279362306a36Sopenharmony_ci return SUCCESS; 279462306a36Sopenharmony_ci ch = &target->ch[ch_idx]; 279562306a36Sopenharmony_ci if (!srp_claim_req(ch, req, NULL, scmnd)) 279662306a36Sopenharmony_ci return SUCCESS; 279762306a36Sopenharmony_ci shost_printk(KERN_ERR, target->scsi_host, 279862306a36Sopenharmony_ci "Sending SRP abort for tag %#x\n", tag); 279962306a36Sopenharmony_ci if (srp_send_tsk_mgmt(ch, tag, scmnd->device->lun, 280062306a36Sopenharmony_ci SRP_TSK_ABORT_TASK, NULL) == 0) { 280162306a36Sopenharmony_ci srp_free_req(ch, req, scmnd, 0); 280262306a36Sopenharmony_ci return SUCCESS; 280362306a36Sopenharmony_ci } 280462306a36Sopenharmony_ci if (target->rport->state == SRP_RPORT_LOST) 280562306a36Sopenharmony_ci return FAST_IO_FAIL; 280662306a36Sopenharmony_ci 280762306a36Sopenharmony_ci return FAILED; 280862306a36Sopenharmony_ci} 280962306a36Sopenharmony_ci 281062306a36Sopenharmony_cistatic int srp_reset_device(struct scsi_cmnd *scmnd) 281162306a36Sopenharmony_ci{ 281262306a36Sopenharmony_ci struct srp_target_port *target = host_to_target(scmnd->device->host); 281362306a36Sopenharmony_ci struct srp_rdma_ch *ch; 281462306a36Sopenharmony_ci u8 status; 281562306a36Sopenharmony_ci 281662306a36Sopenharmony_ci shost_printk(KERN_ERR, target->scsi_host, "SRP reset_device called\n"); 281762306a36Sopenharmony_ci 281862306a36Sopenharmony_ci ch = &target->ch[0]; 281962306a36Sopenharmony_ci if (srp_send_tsk_mgmt(ch, SRP_TAG_NO_REQ, scmnd->device->lun, 282062306a36Sopenharmony_ci SRP_TSK_LUN_RESET, &status)) 282162306a36Sopenharmony_ci return FAILED; 282262306a36Sopenharmony_ci if (status) 282362306a36Sopenharmony_ci return FAILED; 282462306a36Sopenharmony_ci 282562306a36Sopenharmony_ci return SUCCESS; 282662306a36Sopenharmony_ci} 282762306a36Sopenharmony_ci 282862306a36Sopenharmony_cistatic int srp_reset_host(struct scsi_cmnd *scmnd) 282962306a36Sopenharmony_ci{ 283062306a36Sopenharmony_ci struct srp_target_port *target = host_to_target(scmnd->device->host); 283162306a36Sopenharmony_ci 283262306a36Sopenharmony_ci shost_printk(KERN_ERR, target->scsi_host, PFX "SRP reset_host called\n"); 283362306a36Sopenharmony_ci 283462306a36Sopenharmony_ci return srp_reconnect_rport(target->rport) == 0 ? SUCCESS : FAILED; 283562306a36Sopenharmony_ci} 283662306a36Sopenharmony_ci 283762306a36Sopenharmony_cistatic int srp_target_alloc(struct scsi_target *starget) 283862306a36Sopenharmony_ci{ 283962306a36Sopenharmony_ci struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); 284062306a36Sopenharmony_ci struct srp_target_port *target = host_to_target(shost); 284162306a36Sopenharmony_ci 284262306a36Sopenharmony_ci if (target->target_can_queue) 284362306a36Sopenharmony_ci starget->can_queue = target->target_can_queue; 284462306a36Sopenharmony_ci return 0; 284562306a36Sopenharmony_ci} 284662306a36Sopenharmony_ci 284762306a36Sopenharmony_cistatic int srp_slave_configure(struct scsi_device *sdev) 284862306a36Sopenharmony_ci{ 284962306a36Sopenharmony_ci struct Scsi_Host *shost = sdev->host; 285062306a36Sopenharmony_ci struct srp_target_port *target = host_to_target(shost); 285162306a36Sopenharmony_ci struct request_queue *q = sdev->request_queue; 285262306a36Sopenharmony_ci unsigned long timeout; 285362306a36Sopenharmony_ci 285462306a36Sopenharmony_ci if (sdev->type == TYPE_DISK) { 285562306a36Sopenharmony_ci timeout = max_t(unsigned, 30 * HZ, target->rq_tmo_jiffies); 285662306a36Sopenharmony_ci blk_queue_rq_timeout(q, timeout); 285762306a36Sopenharmony_ci } 285862306a36Sopenharmony_ci 285962306a36Sopenharmony_ci return 0; 286062306a36Sopenharmony_ci} 286162306a36Sopenharmony_ci 286262306a36Sopenharmony_cistatic ssize_t id_ext_show(struct device *dev, struct device_attribute *attr, 286362306a36Sopenharmony_ci char *buf) 286462306a36Sopenharmony_ci{ 286562306a36Sopenharmony_ci struct srp_target_port *target = host_to_target(class_to_shost(dev)); 286662306a36Sopenharmony_ci 286762306a36Sopenharmony_ci return sysfs_emit(buf, "0x%016llx\n", be64_to_cpu(target->id_ext)); 286862306a36Sopenharmony_ci} 286962306a36Sopenharmony_ci 287062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(id_ext); 287162306a36Sopenharmony_ci 287262306a36Sopenharmony_cistatic ssize_t ioc_guid_show(struct device *dev, struct device_attribute *attr, 287362306a36Sopenharmony_ci char *buf) 287462306a36Sopenharmony_ci{ 287562306a36Sopenharmony_ci struct srp_target_port *target = host_to_target(class_to_shost(dev)); 287662306a36Sopenharmony_ci 287762306a36Sopenharmony_ci return sysfs_emit(buf, "0x%016llx\n", be64_to_cpu(target->ioc_guid)); 287862306a36Sopenharmony_ci} 287962306a36Sopenharmony_ci 288062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(ioc_guid); 288162306a36Sopenharmony_ci 288262306a36Sopenharmony_cistatic ssize_t service_id_show(struct device *dev, 288362306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 288462306a36Sopenharmony_ci{ 288562306a36Sopenharmony_ci struct srp_target_port *target = host_to_target(class_to_shost(dev)); 288662306a36Sopenharmony_ci 288762306a36Sopenharmony_ci if (target->using_rdma_cm) 288862306a36Sopenharmony_ci return -ENOENT; 288962306a36Sopenharmony_ci return sysfs_emit(buf, "0x%016llx\n", 289062306a36Sopenharmony_ci be64_to_cpu(target->ib_cm.service_id)); 289162306a36Sopenharmony_ci} 289262306a36Sopenharmony_ci 289362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(service_id); 289462306a36Sopenharmony_ci 289562306a36Sopenharmony_cistatic ssize_t pkey_show(struct device *dev, struct device_attribute *attr, 289662306a36Sopenharmony_ci char *buf) 289762306a36Sopenharmony_ci{ 289862306a36Sopenharmony_ci struct srp_target_port *target = host_to_target(class_to_shost(dev)); 289962306a36Sopenharmony_ci 290062306a36Sopenharmony_ci if (target->using_rdma_cm) 290162306a36Sopenharmony_ci return -ENOENT; 290262306a36Sopenharmony_ci 290362306a36Sopenharmony_ci return sysfs_emit(buf, "0x%04x\n", be16_to_cpu(target->ib_cm.pkey)); 290462306a36Sopenharmony_ci} 290562306a36Sopenharmony_ci 290662306a36Sopenharmony_cistatic DEVICE_ATTR_RO(pkey); 290762306a36Sopenharmony_ci 290862306a36Sopenharmony_cistatic ssize_t sgid_show(struct device *dev, struct device_attribute *attr, 290962306a36Sopenharmony_ci char *buf) 291062306a36Sopenharmony_ci{ 291162306a36Sopenharmony_ci struct srp_target_port *target = host_to_target(class_to_shost(dev)); 291262306a36Sopenharmony_ci 291362306a36Sopenharmony_ci return sysfs_emit(buf, "%pI6\n", target->sgid.raw); 291462306a36Sopenharmony_ci} 291562306a36Sopenharmony_ci 291662306a36Sopenharmony_cistatic DEVICE_ATTR_RO(sgid); 291762306a36Sopenharmony_ci 291862306a36Sopenharmony_cistatic ssize_t dgid_show(struct device *dev, struct device_attribute *attr, 291962306a36Sopenharmony_ci char *buf) 292062306a36Sopenharmony_ci{ 292162306a36Sopenharmony_ci struct srp_target_port *target = host_to_target(class_to_shost(dev)); 292262306a36Sopenharmony_ci struct srp_rdma_ch *ch = &target->ch[0]; 292362306a36Sopenharmony_ci 292462306a36Sopenharmony_ci if (target->using_rdma_cm) 292562306a36Sopenharmony_ci return -ENOENT; 292662306a36Sopenharmony_ci 292762306a36Sopenharmony_ci return sysfs_emit(buf, "%pI6\n", ch->ib_cm.path.dgid.raw); 292862306a36Sopenharmony_ci} 292962306a36Sopenharmony_ci 293062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(dgid); 293162306a36Sopenharmony_ci 293262306a36Sopenharmony_cistatic ssize_t orig_dgid_show(struct device *dev, struct device_attribute *attr, 293362306a36Sopenharmony_ci char *buf) 293462306a36Sopenharmony_ci{ 293562306a36Sopenharmony_ci struct srp_target_port *target = host_to_target(class_to_shost(dev)); 293662306a36Sopenharmony_ci 293762306a36Sopenharmony_ci if (target->using_rdma_cm) 293862306a36Sopenharmony_ci return -ENOENT; 293962306a36Sopenharmony_ci 294062306a36Sopenharmony_ci return sysfs_emit(buf, "%pI6\n", target->ib_cm.orig_dgid.raw); 294162306a36Sopenharmony_ci} 294262306a36Sopenharmony_ci 294362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(orig_dgid); 294462306a36Sopenharmony_ci 294562306a36Sopenharmony_cistatic ssize_t req_lim_show(struct device *dev, struct device_attribute *attr, 294662306a36Sopenharmony_ci char *buf) 294762306a36Sopenharmony_ci{ 294862306a36Sopenharmony_ci struct srp_target_port *target = host_to_target(class_to_shost(dev)); 294962306a36Sopenharmony_ci struct srp_rdma_ch *ch; 295062306a36Sopenharmony_ci int i, req_lim = INT_MAX; 295162306a36Sopenharmony_ci 295262306a36Sopenharmony_ci for (i = 0; i < target->ch_count; i++) { 295362306a36Sopenharmony_ci ch = &target->ch[i]; 295462306a36Sopenharmony_ci req_lim = min(req_lim, ch->req_lim); 295562306a36Sopenharmony_ci } 295662306a36Sopenharmony_ci 295762306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", req_lim); 295862306a36Sopenharmony_ci} 295962306a36Sopenharmony_ci 296062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(req_lim); 296162306a36Sopenharmony_ci 296262306a36Sopenharmony_cistatic ssize_t zero_req_lim_show(struct device *dev, 296362306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 296462306a36Sopenharmony_ci{ 296562306a36Sopenharmony_ci struct srp_target_port *target = host_to_target(class_to_shost(dev)); 296662306a36Sopenharmony_ci 296762306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", target->zero_req_lim); 296862306a36Sopenharmony_ci} 296962306a36Sopenharmony_ci 297062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(zero_req_lim); 297162306a36Sopenharmony_ci 297262306a36Sopenharmony_cistatic ssize_t local_ib_port_show(struct device *dev, 297362306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 297462306a36Sopenharmony_ci{ 297562306a36Sopenharmony_ci struct srp_target_port *target = host_to_target(class_to_shost(dev)); 297662306a36Sopenharmony_ci 297762306a36Sopenharmony_ci return sysfs_emit(buf, "%u\n", target->srp_host->port); 297862306a36Sopenharmony_ci} 297962306a36Sopenharmony_ci 298062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(local_ib_port); 298162306a36Sopenharmony_ci 298262306a36Sopenharmony_cistatic ssize_t local_ib_device_show(struct device *dev, 298362306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 298462306a36Sopenharmony_ci{ 298562306a36Sopenharmony_ci struct srp_target_port *target = host_to_target(class_to_shost(dev)); 298662306a36Sopenharmony_ci 298762306a36Sopenharmony_ci return sysfs_emit(buf, "%s\n", 298862306a36Sopenharmony_ci dev_name(&target->srp_host->srp_dev->dev->dev)); 298962306a36Sopenharmony_ci} 299062306a36Sopenharmony_ci 299162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(local_ib_device); 299262306a36Sopenharmony_ci 299362306a36Sopenharmony_cistatic ssize_t ch_count_show(struct device *dev, struct device_attribute *attr, 299462306a36Sopenharmony_ci char *buf) 299562306a36Sopenharmony_ci{ 299662306a36Sopenharmony_ci struct srp_target_port *target = host_to_target(class_to_shost(dev)); 299762306a36Sopenharmony_ci 299862306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", target->ch_count); 299962306a36Sopenharmony_ci} 300062306a36Sopenharmony_ci 300162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(ch_count); 300262306a36Sopenharmony_ci 300362306a36Sopenharmony_cistatic ssize_t comp_vector_show(struct device *dev, 300462306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 300562306a36Sopenharmony_ci{ 300662306a36Sopenharmony_ci struct srp_target_port *target = host_to_target(class_to_shost(dev)); 300762306a36Sopenharmony_ci 300862306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", target->comp_vector); 300962306a36Sopenharmony_ci} 301062306a36Sopenharmony_ci 301162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(comp_vector); 301262306a36Sopenharmony_ci 301362306a36Sopenharmony_cistatic ssize_t tl_retry_count_show(struct device *dev, 301462306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 301562306a36Sopenharmony_ci{ 301662306a36Sopenharmony_ci struct srp_target_port *target = host_to_target(class_to_shost(dev)); 301762306a36Sopenharmony_ci 301862306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", target->tl_retry_count); 301962306a36Sopenharmony_ci} 302062306a36Sopenharmony_ci 302162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(tl_retry_count); 302262306a36Sopenharmony_ci 302362306a36Sopenharmony_cistatic ssize_t cmd_sg_entries_show(struct device *dev, 302462306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 302562306a36Sopenharmony_ci{ 302662306a36Sopenharmony_ci struct srp_target_port *target = host_to_target(class_to_shost(dev)); 302762306a36Sopenharmony_ci 302862306a36Sopenharmony_ci return sysfs_emit(buf, "%u\n", target->cmd_sg_cnt); 302962306a36Sopenharmony_ci} 303062306a36Sopenharmony_ci 303162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(cmd_sg_entries); 303262306a36Sopenharmony_ci 303362306a36Sopenharmony_cistatic ssize_t allow_ext_sg_show(struct device *dev, 303462306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 303562306a36Sopenharmony_ci{ 303662306a36Sopenharmony_ci struct srp_target_port *target = host_to_target(class_to_shost(dev)); 303762306a36Sopenharmony_ci 303862306a36Sopenharmony_ci return sysfs_emit(buf, "%s\n", target->allow_ext_sg ? "true" : "false"); 303962306a36Sopenharmony_ci} 304062306a36Sopenharmony_ci 304162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(allow_ext_sg); 304262306a36Sopenharmony_ci 304362306a36Sopenharmony_cistatic struct attribute *srp_host_attrs[] = { 304462306a36Sopenharmony_ci &dev_attr_id_ext.attr, 304562306a36Sopenharmony_ci &dev_attr_ioc_guid.attr, 304662306a36Sopenharmony_ci &dev_attr_service_id.attr, 304762306a36Sopenharmony_ci &dev_attr_pkey.attr, 304862306a36Sopenharmony_ci &dev_attr_sgid.attr, 304962306a36Sopenharmony_ci &dev_attr_dgid.attr, 305062306a36Sopenharmony_ci &dev_attr_orig_dgid.attr, 305162306a36Sopenharmony_ci &dev_attr_req_lim.attr, 305262306a36Sopenharmony_ci &dev_attr_zero_req_lim.attr, 305362306a36Sopenharmony_ci &dev_attr_local_ib_port.attr, 305462306a36Sopenharmony_ci &dev_attr_local_ib_device.attr, 305562306a36Sopenharmony_ci &dev_attr_ch_count.attr, 305662306a36Sopenharmony_ci &dev_attr_comp_vector.attr, 305762306a36Sopenharmony_ci &dev_attr_tl_retry_count.attr, 305862306a36Sopenharmony_ci &dev_attr_cmd_sg_entries.attr, 305962306a36Sopenharmony_ci &dev_attr_allow_ext_sg.attr, 306062306a36Sopenharmony_ci NULL 306162306a36Sopenharmony_ci}; 306262306a36Sopenharmony_ci 306362306a36Sopenharmony_ciATTRIBUTE_GROUPS(srp_host); 306462306a36Sopenharmony_ci 306562306a36Sopenharmony_cistatic const struct scsi_host_template srp_template = { 306662306a36Sopenharmony_ci .module = THIS_MODULE, 306762306a36Sopenharmony_ci .name = "InfiniBand SRP initiator", 306862306a36Sopenharmony_ci .proc_name = DRV_NAME, 306962306a36Sopenharmony_ci .target_alloc = srp_target_alloc, 307062306a36Sopenharmony_ci .slave_configure = srp_slave_configure, 307162306a36Sopenharmony_ci .info = srp_target_info, 307262306a36Sopenharmony_ci .init_cmd_priv = srp_init_cmd_priv, 307362306a36Sopenharmony_ci .exit_cmd_priv = srp_exit_cmd_priv, 307462306a36Sopenharmony_ci .queuecommand = srp_queuecommand, 307562306a36Sopenharmony_ci .change_queue_depth = srp_change_queue_depth, 307662306a36Sopenharmony_ci .eh_timed_out = srp_timed_out, 307762306a36Sopenharmony_ci .eh_abort_handler = srp_abort, 307862306a36Sopenharmony_ci .eh_device_reset_handler = srp_reset_device, 307962306a36Sopenharmony_ci .eh_host_reset_handler = srp_reset_host, 308062306a36Sopenharmony_ci .skip_settle_delay = true, 308162306a36Sopenharmony_ci .sg_tablesize = SRP_DEF_SG_TABLESIZE, 308262306a36Sopenharmony_ci .can_queue = SRP_DEFAULT_CMD_SQ_SIZE, 308362306a36Sopenharmony_ci .this_id = -1, 308462306a36Sopenharmony_ci .cmd_per_lun = SRP_DEFAULT_CMD_SQ_SIZE, 308562306a36Sopenharmony_ci .shost_groups = srp_host_groups, 308662306a36Sopenharmony_ci .track_queue_depth = 1, 308762306a36Sopenharmony_ci .cmd_size = sizeof(struct srp_request), 308862306a36Sopenharmony_ci}; 308962306a36Sopenharmony_ci 309062306a36Sopenharmony_cistatic int srp_sdev_count(struct Scsi_Host *host) 309162306a36Sopenharmony_ci{ 309262306a36Sopenharmony_ci struct scsi_device *sdev; 309362306a36Sopenharmony_ci int c = 0; 309462306a36Sopenharmony_ci 309562306a36Sopenharmony_ci shost_for_each_device(sdev, host) 309662306a36Sopenharmony_ci c++; 309762306a36Sopenharmony_ci 309862306a36Sopenharmony_ci return c; 309962306a36Sopenharmony_ci} 310062306a36Sopenharmony_ci 310162306a36Sopenharmony_ci/* 310262306a36Sopenharmony_ci * Return values: 310362306a36Sopenharmony_ci * < 0 upon failure. Caller is responsible for SRP target port cleanup. 310462306a36Sopenharmony_ci * 0 and target->state == SRP_TARGET_REMOVED if asynchronous target port 310562306a36Sopenharmony_ci * removal has been scheduled. 310662306a36Sopenharmony_ci * 0 and target->state != SRP_TARGET_REMOVED upon success. 310762306a36Sopenharmony_ci */ 310862306a36Sopenharmony_cistatic int srp_add_target(struct srp_host *host, struct srp_target_port *target) 310962306a36Sopenharmony_ci{ 311062306a36Sopenharmony_ci struct srp_rport_identifiers ids; 311162306a36Sopenharmony_ci struct srp_rport *rport; 311262306a36Sopenharmony_ci 311362306a36Sopenharmony_ci target->state = SRP_TARGET_SCANNING; 311462306a36Sopenharmony_ci sprintf(target->target_name, "SRP.T10:%016llX", 311562306a36Sopenharmony_ci be64_to_cpu(target->id_ext)); 311662306a36Sopenharmony_ci 311762306a36Sopenharmony_ci if (scsi_add_host(target->scsi_host, host->srp_dev->dev->dev.parent)) 311862306a36Sopenharmony_ci return -ENODEV; 311962306a36Sopenharmony_ci 312062306a36Sopenharmony_ci memcpy(ids.port_id, &target->id_ext, 8); 312162306a36Sopenharmony_ci memcpy(ids.port_id + 8, &target->ioc_guid, 8); 312262306a36Sopenharmony_ci ids.roles = SRP_RPORT_ROLE_TARGET; 312362306a36Sopenharmony_ci rport = srp_rport_add(target->scsi_host, &ids); 312462306a36Sopenharmony_ci if (IS_ERR(rport)) { 312562306a36Sopenharmony_ci scsi_remove_host(target->scsi_host); 312662306a36Sopenharmony_ci return PTR_ERR(rport); 312762306a36Sopenharmony_ci } 312862306a36Sopenharmony_ci 312962306a36Sopenharmony_ci rport->lld_data = target; 313062306a36Sopenharmony_ci target->rport = rport; 313162306a36Sopenharmony_ci 313262306a36Sopenharmony_ci spin_lock(&host->target_lock); 313362306a36Sopenharmony_ci list_add_tail(&target->list, &host->target_list); 313462306a36Sopenharmony_ci spin_unlock(&host->target_lock); 313562306a36Sopenharmony_ci 313662306a36Sopenharmony_ci scsi_scan_target(&target->scsi_host->shost_gendev, 313762306a36Sopenharmony_ci 0, target->scsi_id, SCAN_WILD_CARD, SCSI_SCAN_INITIAL); 313862306a36Sopenharmony_ci 313962306a36Sopenharmony_ci if (srp_connected_ch(target) < target->ch_count || 314062306a36Sopenharmony_ci target->qp_in_error) { 314162306a36Sopenharmony_ci shost_printk(KERN_INFO, target->scsi_host, 314262306a36Sopenharmony_ci PFX "SCSI scan failed - removing SCSI host\n"); 314362306a36Sopenharmony_ci srp_queue_remove_work(target); 314462306a36Sopenharmony_ci goto out; 314562306a36Sopenharmony_ci } 314662306a36Sopenharmony_ci 314762306a36Sopenharmony_ci pr_debug("%s: SCSI scan succeeded - detected %d LUNs\n", 314862306a36Sopenharmony_ci dev_name(&target->scsi_host->shost_gendev), 314962306a36Sopenharmony_ci srp_sdev_count(target->scsi_host)); 315062306a36Sopenharmony_ci 315162306a36Sopenharmony_ci spin_lock_irq(&target->lock); 315262306a36Sopenharmony_ci if (target->state == SRP_TARGET_SCANNING) 315362306a36Sopenharmony_ci target->state = SRP_TARGET_LIVE; 315462306a36Sopenharmony_ci spin_unlock_irq(&target->lock); 315562306a36Sopenharmony_ci 315662306a36Sopenharmony_ciout: 315762306a36Sopenharmony_ci return 0; 315862306a36Sopenharmony_ci} 315962306a36Sopenharmony_ci 316062306a36Sopenharmony_cistatic void srp_release_dev(struct device *dev) 316162306a36Sopenharmony_ci{ 316262306a36Sopenharmony_ci struct srp_host *host = 316362306a36Sopenharmony_ci container_of(dev, struct srp_host, dev); 316462306a36Sopenharmony_ci 316562306a36Sopenharmony_ci kfree(host); 316662306a36Sopenharmony_ci} 316762306a36Sopenharmony_ci 316862306a36Sopenharmony_cistatic struct attribute *srp_class_attrs[]; 316962306a36Sopenharmony_ci 317062306a36Sopenharmony_ciATTRIBUTE_GROUPS(srp_class); 317162306a36Sopenharmony_ci 317262306a36Sopenharmony_cistatic struct class srp_class = { 317362306a36Sopenharmony_ci .name = "infiniband_srp", 317462306a36Sopenharmony_ci .dev_groups = srp_class_groups, 317562306a36Sopenharmony_ci .dev_release = srp_release_dev 317662306a36Sopenharmony_ci}; 317762306a36Sopenharmony_ci 317862306a36Sopenharmony_ci/** 317962306a36Sopenharmony_ci * srp_conn_unique() - check whether the connection to a target is unique 318062306a36Sopenharmony_ci * @host: SRP host. 318162306a36Sopenharmony_ci * @target: SRP target port. 318262306a36Sopenharmony_ci */ 318362306a36Sopenharmony_cistatic bool srp_conn_unique(struct srp_host *host, 318462306a36Sopenharmony_ci struct srp_target_port *target) 318562306a36Sopenharmony_ci{ 318662306a36Sopenharmony_ci struct srp_target_port *t; 318762306a36Sopenharmony_ci bool ret = false; 318862306a36Sopenharmony_ci 318962306a36Sopenharmony_ci if (target->state == SRP_TARGET_REMOVED) 319062306a36Sopenharmony_ci goto out; 319162306a36Sopenharmony_ci 319262306a36Sopenharmony_ci ret = true; 319362306a36Sopenharmony_ci 319462306a36Sopenharmony_ci spin_lock(&host->target_lock); 319562306a36Sopenharmony_ci list_for_each_entry(t, &host->target_list, list) { 319662306a36Sopenharmony_ci if (t != target && 319762306a36Sopenharmony_ci target->id_ext == t->id_ext && 319862306a36Sopenharmony_ci target->ioc_guid == t->ioc_guid && 319962306a36Sopenharmony_ci target->initiator_ext == t->initiator_ext) { 320062306a36Sopenharmony_ci ret = false; 320162306a36Sopenharmony_ci break; 320262306a36Sopenharmony_ci } 320362306a36Sopenharmony_ci } 320462306a36Sopenharmony_ci spin_unlock(&host->target_lock); 320562306a36Sopenharmony_ci 320662306a36Sopenharmony_ciout: 320762306a36Sopenharmony_ci return ret; 320862306a36Sopenharmony_ci} 320962306a36Sopenharmony_ci 321062306a36Sopenharmony_ci/* 321162306a36Sopenharmony_ci * Target ports are added by writing 321262306a36Sopenharmony_ci * 321362306a36Sopenharmony_ci * id_ext=<SRP ID ext>,ioc_guid=<SRP IOC GUID>,dgid=<dest GID>, 321462306a36Sopenharmony_ci * pkey=<P_Key>,service_id=<service ID> 321562306a36Sopenharmony_ci * or 321662306a36Sopenharmony_ci * id_ext=<SRP ID ext>,ioc_guid=<SRP IOC GUID>, 321762306a36Sopenharmony_ci * [src=<IPv4 address>,]dest=<IPv4 address>:<port number> 321862306a36Sopenharmony_ci * 321962306a36Sopenharmony_ci * to the add_target sysfs attribute. 322062306a36Sopenharmony_ci */ 322162306a36Sopenharmony_cienum { 322262306a36Sopenharmony_ci SRP_OPT_ERR = 0, 322362306a36Sopenharmony_ci SRP_OPT_ID_EXT = 1 << 0, 322462306a36Sopenharmony_ci SRP_OPT_IOC_GUID = 1 << 1, 322562306a36Sopenharmony_ci SRP_OPT_DGID = 1 << 2, 322662306a36Sopenharmony_ci SRP_OPT_PKEY = 1 << 3, 322762306a36Sopenharmony_ci SRP_OPT_SERVICE_ID = 1 << 4, 322862306a36Sopenharmony_ci SRP_OPT_MAX_SECT = 1 << 5, 322962306a36Sopenharmony_ci SRP_OPT_MAX_CMD_PER_LUN = 1 << 6, 323062306a36Sopenharmony_ci SRP_OPT_IO_CLASS = 1 << 7, 323162306a36Sopenharmony_ci SRP_OPT_INITIATOR_EXT = 1 << 8, 323262306a36Sopenharmony_ci SRP_OPT_CMD_SG_ENTRIES = 1 << 9, 323362306a36Sopenharmony_ci SRP_OPT_ALLOW_EXT_SG = 1 << 10, 323462306a36Sopenharmony_ci SRP_OPT_SG_TABLESIZE = 1 << 11, 323562306a36Sopenharmony_ci SRP_OPT_COMP_VECTOR = 1 << 12, 323662306a36Sopenharmony_ci SRP_OPT_TL_RETRY_COUNT = 1 << 13, 323762306a36Sopenharmony_ci SRP_OPT_QUEUE_SIZE = 1 << 14, 323862306a36Sopenharmony_ci SRP_OPT_IP_SRC = 1 << 15, 323962306a36Sopenharmony_ci SRP_OPT_IP_DEST = 1 << 16, 324062306a36Sopenharmony_ci SRP_OPT_TARGET_CAN_QUEUE= 1 << 17, 324162306a36Sopenharmony_ci SRP_OPT_MAX_IT_IU_SIZE = 1 << 18, 324262306a36Sopenharmony_ci SRP_OPT_CH_COUNT = 1 << 19, 324362306a36Sopenharmony_ci}; 324462306a36Sopenharmony_ci 324562306a36Sopenharmony_cistatic unsigned int srp_opt_mandatory[] = { 324662306a36Sopenharmony_ci SRP_OPT_ID_EXT | 324762306a36Sopenharmony_ci SRP_OPT_IOC_GUID | 324862306a36Sopenharmony_ci SRP_OPT_DGID | 324962306a36Sopenharmony_ci SRP_OPT_PKEY | 325062306a36Sopenharmony_ci SRP_OPT_SERVICE_ID, 325162306a36Sopenharmony_ci SRP_OPT_ID_EXT | 325262306a36Sopenharmony_ci SRP_OPT_IOC_GUID | 325362306a36Sopenharmony_ci SRP_OPT_IP_DEST, 325462306a36Sopenharmony_ci}; 325562306a36Sopenharmony_ci 325662306a36Sopenharmony_cistatic const match_table_t srp_opt_tokens = { 325762306a36Sopenharmony_ci { SRP_OPT_ID_EXT, "id_ext=%s" }, 325862306a36Sopenharmony_ci { SRP_OPT_IOC_GUID, "ioc_guid=%s" }, 325962306a36Sopenharmony_ci { SRP_OPT_DGID, "dgid=%s" }, 326062306a36Sopenharmony_ci { SRP_OPT_PKEY, "pkey=%x" }, 326162306a36Sopenharmony_ci { SRP_OPT_SERVICE_ID, "service_id=%s" }, 326262306a36Sopenharmony_ci { SRP_OPT_MAX_SECT, "max_sect=%d" }, 326362306a36Sopenharmony_ci { SRP_OPT_MAX_CMD_PER_LUN, "max_cmd_per_lun=%d" }, 326462306a36Sopenharmony_ci { SRP_OPT_TARGET_CAN_QUEUE, "target_can_queue=%d" }, 326562306a36Sopenharmony_ci { SRP_OPT_IO_CLASS, "io_class=%x" }, 326662306a36Sopenharmony_ci { SRP_OPT_INITIATOR_EXT, "initiator_ext=%s" }, 326762306a36Sopenharmony_ci { SRP_OPT_CMD_SG_ENTRIES, "cmd_sg_entries=%u" }, 326862306a36Sopenharmony_ci { SRP_OPT_ALLOW_EXT_SG, "allow_ext_sg=%u" }, 326962306a36Sopenharmony_ci { SRP_OPT_SG_TABLESIZE, "sg_tablesize=%u" }, 327062306a36Sopenharmony_ci { SRP_OPT_COMP_VECTOR, "comp_vector=%u" }, 327162306a36Sopenharmony_ci { SRP_OPT_TL_RETRY_COUNT, "tl_retry_count=%u" }, 327262306a36Sopenharmony_ci { SRP_OPT_QUEUE_SIZE, "queue_size=%d" }, 327362306a36Sopenharmony_ci { SRP_OPT_IP_SRC, "src=%s" }, 327462306a36Sopenharmony_ci { SRP_OPT_IP_DEST, "dest=%s" }, 327562306a36Sopenharmony_ci { SRP_OPT_MAX_IT_IU_SIZE, "max_it_iu_size=%d" }, 327662306a36Sopenharmony_ci { SRP_OPT_CH_COUNT, "ch_count=%u", }, 327762306a36Sopenharmony_ci { SRP_OPT_ERR, NULL } 327862306a36Sopenharmony_ci}; 327962306a36Sopenharmony_ci 328062306a36Sopenharmony_ci/** 328162306a36Sopenharmony_ci * srp_parse_in - parse an IP address and port number combination 328262306a36Sopenharmony_ci * @net: [in] Network namespace. 328362306a36Sopenharmony_ci * @sa: [out] Address family, IP address and port number. 328462306a36Sopenharmony_ci * @addr_port_str: [in] IP address and port number. 328562306a36Sopenharmony_ci * @has_port: [out] Whether or not @addr_port_str includes a port number. 328662306a36Sopenharmony_ci * 328762306a36Sopenharmony_ci * Parse the following address formats: 328862306a36Sopenharmony_ci * - IPv4: <ip_address>:<port>, e.g. 1.2.3.4:5. 328962306a36Sopenharmony_ci * - IPv6: \[<ipv6_address>\]:<port>, e.g. [1::2:3%4]:5. 329062306a36Sopenharmony_ci */ 329162306a36Sopenharmony_cistatic int srp_parse_in(struct net *net, struct sockaddr_storage *sa, 329262306a36Sopenharmony_ci const char *addr_port_str, bool *has_port) 329362306a36Sopenharmony_ci{ 329462306a36Sopenharmony_ci char *addr_end, *addr = kstrdup(addr_port_str, GFP_KERNEL); 329562306a36Sopenharmony_ci char *port_str; 329662306a36Sopenharmony_ci int ret; 329762306a36Sopenharmony_ci 329862306a36Sopenharmony_ci if (!addr) 329962306a36Sopenharmony_ci return -ENOMEM; 330062306a36Sopenharmony_ci port_str = strrchr(addr, ':'); 330162306a36Sopenharmony_ci if (port_str && strchr(port_str, ']')) 330262306a36Sopenharmony_ci port_str = NULL; 330362306a36Sopenharmony_ci if (port_str) 330462306a36Sopenharmony_ci *port_str++ = '\0'; 330562306a36Sopenharmony_ci if (has_port) 330662306a36Sopenharmony_ci *has_port = port_str != NULL; 330762306a36Sopenharmony_ci ret = inet_pton_with_scope(net, AF_INET, addr, port_str, sa); 330862306a36Sopenharmony_ci if (ret && addr[0]) { 330962306a36Sopenharmony_ci addr_end = addr + strlen(addr) - 1; 331062306a36Sopenharmony_ci if (addr[0] == '[' && *addr_end == ']') { 331162306a36Sopenharmony_ci *addr_end = '\0'; 331262306a36Sopenharmony_ci ret = inet_pton_with_scope(net, AF_INET6, addr + 1, 331362306a36Sopenharmony_ci port_str, sa); 331462306a36Sopenharmony_ci } 331562306a36Sopenharmony_ci } 331662306a36Sopenharmony_ci kfree(addr); 331762306a36Sopenharmony_ci pr_debug("%s -> %pISpfsc\n", addr_port_str, sa); 331862306a36Sopenharmony_ci return ret; 331962306a36Sopenharmony_ci} 332062306a36Sopenharmony_ci 332162306a36Sopenharmony_cistatic int srp_parse_options(struct net *net, const char *buf, 332262306a36Sopenharmony_ci struct srp_target_port *target) 332362306a36Sopenharmony_ci{ 332462306a36Sopenharmony_ci char *options, *sep_opt; 332562306a36Sopenharmony_ci char *p; 332662306a36Sopenharmony_ci substring_t args[MAX_OPT_ARGS]; 332762306a36Sopenharmony_ci unsigned long long ull; 332862306a36Sopenharmony_ci bool has_port; 332962306a36Sopenharmony_ci int opt_mask = 0; 333062306a36Sopenharmony_ci int token; 333162306a36Sopenharmony_ci int ret = -EINVAL; 333262306a36Sopenharmony_ci int i; 333362306a36Sopenharmony_ci 333462306a36Sopenharmony_ci options = kstrdup(buf, GFP_KERNEL); 333562306a36Sopenharmony_ci if (!options) 333662306a36Sopenharmony_ci return -ENOMEM; 333762306a36Sopenharmony_ci 333862306a36Sopenharmony_ci sep_opt = options; 333962306a36Sopenharmony_ci while ((p = strsep(&sep_opt, ",\n")) != NULL) { 334062306a36Sopenharmony_ci if (!*p) 334162306a36Sopenharmony_ci continue; 334262306a36Sopenharmony_ci 334362306a36Sopenharmony_ci token = match_token(p, srp_opt_tokens, args); 334462306a36Sopenharmony_ci opt_mask |= token; 334562306a36Sopenharmony_ci 334662306a36Sopenharmony_ci switch (token) { 334762306a36Sopenharmony_ci case SRP_OPT_ID_EXT: 334862306a36Sopenharmony_ci p = match_strdup(args); 334962306a36Sopenharmony_ci if (!p) { 335062306a36Sopenharmony_ci ret = -ENOMEM; 335162306a36Sopenharmony_ci goto out; 335262306a36Sopenharmony_ci } 335362306a36Sopenharmony_ci ret = kstrtoull(p, 16, &ull); 335462306a36Sopenharmony_ci if (ret) { 335562306a36Sopenharmony_ci pr_warn("invalid id_ext parameter '%s'\n", p); 335662306a36Sopenharmony_ci kfree(p); 335762306a36Sopenharmony_ci goto out; 335862306a36Sopenharmony_ci } 335962306a36Sopenharmony_ci target->id_ext = cpu_to_be64(ull); 336062306a36Sopenharmony_ci kfree(p); 336162306a36Sopenharmony_ci break; 336262306a36Sopenharmony_ci 336362306a36Sopenharmony_ci case SRP_OPT_IOC_GUID: 336462306a36Sopenharmony_ci p = match_strdup(args); 336562306a36Sopenharmony_ci if (!p) { 336662306a36Sopenharmony_ci ret = -ENOMEM; 336762306a36Sopenharmony_ci goto out; 336862306a36Sopenharmony_ci } 336962306a36Sopenharmony_ci ret = kstrtoull(p, 16, &ull); 337062306a36Sopenharmony_ci if (ret) { 337162306a36Sopenharmony_ci pr_warn("invalid ioc_guid parameter '%s'\n", p); 337262306a36Sopenharmony_ci kfree(p); 337362306a36Sopenharmony_ci goto out; 337462306a36Sopenharmony_ci } 337562306a36Sopenharmony_ci target->ioc_guid = cpu_to_be64(ull); 337662306a36Sopenharmony_ci kfree(p); 337762306a36Sopenharmony_ci break; 337862306a36Sopenharmony_ci 337962306a36Sopenharmony_ci case SRP_OPT_DGID: 338062306a36Sopenharmony_ci p = match_strdup(args); 338162306a36Sopenharmony_ci if (!p) { 338262306a36Sopenharmony_ci ret = -ENOMEM; 338362306a36Sopenharmony_ci goto out; 338462306a36Sopenharmony_ci } 338562306a36Sopenharmony_ci if (strlen(p) != 32) { 338662306a36Sopenharmony_ci pr_warn("bad dest GID parameter '%s'\n", p); 338762306a36Sopenharmony_ci kfree(p); 338862306a36Sopenharmony_ci goto out; 338962306a36Sopenharmony_ci } 339062306a36Sopenharmony_ci 339162306a36Sopenharmony_ci ret = hex2bin(target->ib_cm.orig_dgid.raw, p, 16); 339262306a36Sopenharmony_ci kfree(p); 339362306a36Sopenharmony_ci if (ret < 0) 339462306a36Sopenharmony_ci goto out; 339562306a36Sopenharmony_ci break; 339662306a36Sopenharmony_ci 339762306a36Sopenharmony_ci case SRP_OPT_PKEY: 339862306a36Sopenharmony_ci ret = match_hex(args, &token); 339962306a36Sopenharmony_ci if (ret) { 340062306a36Sopenharmony_ci pr_warn("bad P_Key parameter '%s'\n", p); 340162306a36Sopenharmony_ci goto out; 340262306a36Sopenharmony_ci } 340362306a36Sopenharmony_ci target->ib_cm.pkey = cpu_to_be16(token); 340462306a36Sopenharmony_ci break; 340562306a36Sopenharmony_ci 340662306a36Sopenharmony_ci case SRP_OPT_SERVICE_ID: 340762306a36Sopenharmony_ci p = match_strdup(args); 340862306a36Sopenharmony_ci if (!p) { 340962306a36Sopenharmony_ci ret = -ENOMEM; 341062306a36Sopenharmony_ci goto out; 341162306a36Sopenharmony_ci } 341262306a36Sopenharmony_ci ret = kstrtoull(p, 16, &ull); 341362306a36Sopenharmony_ci if (ret) { 341462306a36Sopenharmony_ci pr_warn("bad service_id parameter '%s'\n", p); 341562306a36Sopenharmony_ci kfree(p); 341662306a36Sopenharmony_ci goto out; 341762306a36Sopenharmony_ci } 341862306a36Sopenharmony_ci target->ib_cm.service_id = cpu_to_be64(ull); 341962306a36Sopenharmony_ci kfree(p); 342062306a36Sopenharmony_ci break; 342162306a36Sopenharmony_ci 342262306a36Sopenharmony_ci case SRP_OPT_IP_SRC: 342362306a36Sopenharmony_ci p = match_strdup(args); 342462306a36Sopenharmony_ci if (!p) { 342562306a36Sopenharmony_ci ret = -ENOMEM; 342662306a36Sopenharmony_ci goto out; 342762306a36Sopenharmony_ci } 342862306a36Sopenharmony_ci ret = srp_parse_in(net, &target->rdma_cm.src.ss, p, 342962306a36Sopenharmony_ci NULL); 343062306a36Sopenharmony_ci if (ret < 0) { 343162306a36Sopenharmony_ci pr_warn("bad source parameter '%s'\n", p); 343262306a36Sopenharmony_ci kfree(p); 343362306a36Sopenharmony_ci goto out; 343462306a36Sopenharmony_ci } 343562306a36Sopenharmony_ci target->rdma_cm.src_specified = true; 343662306a36Sopenharmony_ci kfree(p); 343762306a36Sopenharmony_ci break; 343862306a36Sopenharmony_ci 343962306a36Sopenharmony_ci case SRP_OPT_IP_DEST: 344062306a36Sopenharmony_ci p = match_strdup(args); 344162306a36Sopenharmony_ci if (!p) { 344262306a36Sopenharmony_ci ret = -ENOMEM; 344362306a36Sopenharmony_ci goto out; 344462306a36Sopenharmony_ci } 344562306a36Sopenharmony_ci ret = srp_parse_in(net, &target->rdma_cm.dst.ss, p, 344662306a36Sopenharmony_ci &has_port); 344762306a36Sopenharmony_ci if (!has_port) 344862306a36Sopenharmony_ci ret = -EINVAL; 344962306a36Sopenharmony_ci if (ret < 0) { 345062306a36Sopenharmony_ci pr_warn("bad dest parameter '%s'\n", p); 345162306a36Sopenharmony_ci kfree(p); 345262306a36Sopenharmony_ci goto out; 345362306a36Sopenharmony_ci } 345462306a36Sopenharmony_ci target->using_rdma_cm = true; 345562306a36Sopenharmony_ci kfree(p); 345662306a36Sopenharmony_ci break; 345762306a36Sopenharmony_ci 345862306a36Sopenharmony_ci case SRP_OPT_MAX_SECT: 345962306a36Sopenharmony_ci ret = match_int(args, &token); 346062306a36Sopenharmony_ci if (ret) { 346162306a36Sopenharmony_ci pr_warn("bad max sect parameter '%s'\n", p); 346262306a36Sopenharmony_ci goto out; 346362306a36Sopenharmony_ci } 346462306a36Sopenharmony_ci target->scsi_host->max_sectors = token; 346562306a36Sopenharmony_ci break; 346662306a36Sopenharmony_ci 346762306a36Sopenharmony_ci case SRP_OPT_QUEUE_SIZE: 346862306a36Sopenharmony_ci ret = match_int(args, &token); 346962306a36Sopenharmony_ci if (ret) { 347062306a36Sopenharmony_ci pr_warn("match_int() failed for queue_size parameter '%s', Error %d\n", 347162306a36Sopenharmony_ci p, ret); 347262306a36Sopenharmony_ci goto out; 347362306a36Sopenharmony_ci } 347462306a36Sopenharmony_ci if (token < 1) { 347562306a36Sopenharmony_ci pr_warn("bad queue_size parameter '%s'\n", p); 347662306a36Sopenharmony_ci ret = -EINVAL; 347762306a36Sopenharmony_ci goto out; 347862306a36Sopenharmony_ci } 347962306a36Sopenharmony_ci target->scsi_host->can_queue = token; 348062306a36Sopenharmony_ci target->queue_size = token + SRP_RSP_SQ_SIZE + 348162306a36Sopenharmony_ci SRP_TSK_MGMT_SQ_SIZE; 348262306a36Sopenharmony_ci if (!(opt_mask & SRP_OPT_MAX_CMD_PER_LUN)) 348362306a36Sopenharmony_ci target->scsi_host->cmd_per_lun = token; 348462306a36Sopenharmony_ci break; 348562306a36Sopenharmony_ci 348662306a36Sopenharmony_ci case SRP_OPT_MAX_CMD_PER_LUN: 348762306a36Sopenharmony_ci ret = match_int(args, &token); 348862306a36Sopenharmony_ci if (ret) { 348962306a36Sopenharmony_ci pr_warn("match_int() failed for max cmd_per_lun parameter '%s', Error %d\n", 349062306a36Sopenharmony_ci p, ret); 349162306a36Sopenharmony_ci goto out; 349262306a36Sopenharmony_ci } 349362306a36Sopenharmony_ci if (token < 1) { 349462306a36Sopenharmony_ci pr_warn("bad max cmd_per_lun parameter '%s'\n", 349562306a36Sopenharmony_ci p); 349662306a36Sopenharmony_ci ret = -EINVAL; 349762306a36Sopenharmony_ci goto out; 349862306a36Sopenharmony_ci } 349962306a36Sopenharmony_ci target->scsi_host->cmd_per_lun = token; 350062306a36Sopenharmony_ci break; 350162306a36Sopenharmony_ci 350262306a36Sopenharmony_ci case SRP_OPT_TARGET_CAN_QUEUE: 350362306a36Sopenharmony_ci ret = match_int(args, &token); 350462306a36Sopenharmony_ci if (ret) { 350562306a36Sopenharmony_ci pr_warn("match_int() failed for max target_can_queue parameter '%s', Error %d\n", 350662306a36Sopenharmony_ci p, ret); 350762306a36Sopenharmony_ci goto out; 350862306a36Sopenharmony_ci } 350962306a36Sopenharmony_ci if (token < 1) { 351062306a36Sopenharmony_ci pr_warn("bad max target_can_queue parameter '%s'\n", 351162306a36Sopenharmony_ci p); 351262306a36Sopenharmony_ci ret = -EINVAL; 351362306a36Sopenharmony_ci goto out; 351462306a36Sopenharmony_ci } 351562306a36Sopenharmony_ci target->target_can_queue = token; 351662306a36Sopenharmony_ci break; 351762306a36Sopenharmony_ci 351862306a36Sopenharmony_ci case SRP_OPT_IO_CLASS: 351962306a36Sopenharmony_ci ret = match_hex(args, &token); 352062306a36Sopenharmony_ci if (ret) { 352162306a36Sopenharmony_ci pr_warn("bad IO class parameter '%s'\n", p); 352262306a36Sopenharmony_ci goto out; 352362306a36Sopenharmony_ci } 352462306a36Sopenharmony_ci if (token != SRP_REV10_IB_IO_CLASS && 352562306a36Sopenharmony_ci token != SRP_REV16A_IB_IO_CLASS) { 352662306a36Sopenharmony_ci pr_warn("unknown IO class parameter value %x specified (use %x or %x).\n", 352762306a36Sopenharmony_ci token, SRP_REV10_IB_IO_CLASS, 352862306a36Sopenharmony_ci SRP_REV16A_IB_IO_CLASS); 352962306a36Sopenharmony_ci ret = -EINVAL; 353062306a36Sopenharmony_ci goto out; 353162306a36Sopenharmony_ci } 353262306a36Sopenharmony_ci target->io_class = token; 353362306a36Sopenharmony_ci break; 353462306a36Sopenharmony_ci 353562306a36Sopenharmony_ci case SRP_OPT_INITIATOR_EXT: 353662306a36Sopenharmony_ci p = match_strdup(args); 353762306a36Sopenharmony_ci if (!p) { 353862306a36Sopenharmony_ci ret = -ENOMEM; 353962306a36Sopenharmony_ci goto out; 354062306a36Sopenharmony_ci } 354162306a36Sopenharmony_ci ret = kstrtoull(p, 16, &ull); 354262306a36Sopenharmony_ci if (ret) { 354362306a36Sopenharmony_ci pr_warn("bad initiator_ext value '%s'\n", p); 354462306a36Sopenharmony_ci kfree(p); 354562306a36Sopenharmony_ci goto out; 354662306a36Sopenharmony_ci } 354762306a36Sopenharmony_ci target->initiator_ext = cpu_to_be64(ull); 354862306a36Sopenharmony_ci kfree(p); 354962306a36Sopenharmony_ci break; 355062306a36Sopenharmony_ci 355162306a36Sopenharmony_ci case SRP_OPT_CMD_SG_ENTRIES: 355262306a36Sopenharmony_ci ret = match_int(args, &token); 355362306a36Sopenharmony_ci if (ret) { 355462306a36Sopenharmony_ci pr_warn("match_int() failed for max cmd_sg_entries parameter '%s', Error %d\n", 355562306a36Sopenharmony_ci p, ret); 355662306a36Sopenharmony_ci goto out; 355762306a36Sopenharmony_ci } 355862306a36Sopenharmony_ci if (token < 1 || token > 255) { 355962306a36Sopenharmony_ci pr_warn("bad max cmd_sg_entries parameter '%s'\n", 356062306a36Sopenharmony_ci p); 356162306a36Sopenharmony_ci ret = -EINVAL; 356262306a36Sopenharmony_ci goto out; 356362306a36Sopenharmony_ci } 356462306a36Sopenharmony_ci target->cmd_sg_cnt = token; 356562306a36Sopenharmony_ci break; 356662306a36Sopenharmony_ci 356762306a36Sopenharmony_ci case SRP_OPT_ALLOW_EXT_SG: 356862306a36Sopenharmony_ci ret = match_int(args, &token); 356962306a36Sopenharmony_ci if (ret) { 357062306a36Sopenharmony_ci pr_warn("bad allow_ext_sg parameter '%s'\n", p); 357162306a36Sopenharmony_ci goto out; 357262306a36Sopenharmony_ci } 357362306a36Sopenharmony_ci target->allow_ext_sg = !!token; 357462306a36Sopenharmony_ci break; 357562306a36Sopenharmony_ci 357662306a36Sopenharmony_ci case SRP_OPT_SG_TABLESIZE: 357762306a36Sopenharmony_ci ret = match_int(args, &token); 357862306a36Sopenharmony_ci if (ret) { 357962306a36Sopenharmony_ci pr_warn("match_int() failed for max sg_tablesize parameter '%s', Error %d\n", 358062306a36Sopenharmony_ci p, ret); 358162306a36Sopenharmony_ci goto out; 358262306a36Sopenharmony_ci } 358362306a36Sopenharmony_ci if (token < 1 || token > SG_MAX_SEGMENTS) { 358462306a36Sopenharmony_ci pr_warn("bad max sg_tablesize parameter '%s'\n", 358562306a36Sopenharmony_ci p); 358662306a36Sopenharmony_ci ret = -EINVAL; 358762306a36Sopenharmony_ci goto out; 358862306a36Sopenharmony_ci } 358962306a36Sopenharmony_ci target->sg_tablesize = token; 359062306a36Sopenharmony_ci break; 359162306a36Sopenharmony_ci 359262306a36Sopenharmony_ci case SRP_OPT_COMP_VECTOR: 359362306a36Sopenharmony_ci ret = match_int(args, &token); 359462306a36Sopenharmony_ci if (ret) { 359562306a36Sopenharmony_ci pr_warn("match_int() failed for comp_vector parameter '%s', Error %d\n", 359662306a36Sopenharmony_ci p, ret); 359762306a36Sopenharmony_ci goto out; 359862306a36Sopenharmony_ci } 359962306a36Sopenharmony_ci if (token < 0) { 360062306a36Sopenharmony_ci pr_warn("bad comp_vector parameter '%s'\n", p); 360162306a36Sopenharmony_ci ret = -EINVAL; 360262306a36Sopenharmony_ci goto out; 360362306a36Sopenharmony_ci } 360462306a36Sopenharmony_ci target->comp_vector = token; 360562306a36Sopenharmony_ci break; 360662306a36Sopenharmony_ci 360762306a36Sopenharmony_ci case SRP_OPT_TL_RETRY_COUNT: 360862306a36Sopenharmony_ci ret = match_int(args, &token); 360962306a36Sopenharmony_ci if (ret) { 361062306a36Sopenharmony_ci pr_warn("match_int() failed for tl_retry_count parameter '%s', Error %d\n", 361162306a36Sopenharmony_ci p, ret); 361262306a36Sopenharmony_ci goto out; 361362306a36Sopenharmony_ci } 361462306a36Sopenharmony_ci if (token < 2 || token > 7) { 361562306a36Sopenharmony_ci pr_warn("bad tl_retry_count parameter '%s' (must be a number between 2 and 7)\n", 361662306a36Sopenharmony_ci p); 361762306a36Sopenharmony_ci ret = -EINVAL; 361862306a36Sopenharmony_ci goto out; 361962306a36Sopenharmony_ci } 362062306a36Sopenharmony_ci target->tl_retry_count = token; 362162306a36Sopenharmony_ci break; 362262306a36Sopenharmony_ci 362362306a36Sopenharmony_ci case SRP_OPT_MAX_IT_IU_SIZE: 362462306a36Sopenharmony_ci ret = match_int(args, &token); 362562306a36Sopenharmony_ci if (ret) { 362662306a36Sopenharmony_ci pr_warn("match_int() failed for max it_iu_size parameter '%s', Error %d\n", 362762306a36Sopenharmony_ci p, ret); 362862306a36Sopenharmony_ci goto out; 362962306a36Sopenharmony_ci } 363062306a36Sopenharmony_ci if (token < 0) { 363162306a36Sopenharmony_ci pr_warn("bad maximum initiator to target IU size '%s'\n", p); 363262306a36Sopenharmony_ci ret = -EINVAL; 363362306a36Sopenharmony_ci goto out; 363462306a36Sopenharmony_ci } 363562306a36Sopenharmony_ci target->max_it_iu_size = token; 363662306a36Sopenharmony_ci break; 363762306a36Sopenharmony_ci 363862306a36Sopenharmony_ci case SRP_OPT_CH_COUNT: 363962306a36Sopenharmony_ci ret = match_int(args, &token); 364062306a36Sopenharmony_ci if (ret) { 364162306a36Sopenharmony_ci pr_warn("match_int() failed for channel count parameter '%s', Error %d\n", 364262306a36Sopenharmony_ci p, ret); 364362306a36Sopenharmony_ci goto out; 364462306a36Sopenharmony_ci } 364562306a36Sopenharmony_ci if (token < 1) { 364662306a36Sopenharmony_ci pr_warn("bad channel count %s\n", p); 364762306a36Sopenharmony_ci ret = -EINVAL; 364862306a36Sopenharmony_ci goto out; 364962306a36Sopenharmony_ci } 365062306a36Sopenharmony_ci target->ch_count = token; 365162306a36Sopenharmony_ci break; 365262306a36Sopenharmony_ci 365362306a36Sopenharmony_ci default: 365462306a36Sopenharmony_ci pr_warn("unknown parameter or missing value '%s' in target creation request\n", 365562306a36Sopenharmony_ci p); 365662306a36Sopenharmony_ci ret = -EINVAL; 365762306a36Sopenharmony_ci goto out; 365862306a36Sopenharmony_ci } 365962306a36Sopenharmony_ci } 366062306a36Sopenharmony_ci 366162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(srp_opt_mandatory); i++) { 366262306a36Sopenharmony_ci if ((opt_mask & srp_opt_mandatory[i]) == srp_opt_mandatory[i]) { 366362306a36Sopenharmony_ci ret = 0; 366462306a36Sopenharmony_ci break; 366562306a36Sopenharmony_ci } 366662306a36Sopenharmony_ci } 366762306a36Sopenharmony_ci if (ret) 366862306a36Sopenharmony_ci pr_warn("target creation request is missing one or more parameters\n"); 366962306a36Sopenharmony_ci 367062306a36Sopenharmony_ci if (target->scsi_host->cmd_per_lun > target->scsi_host->can_queue 367162306a36Sopenharmony_ci && (opt_mask & SRP_OPT_MAX_CMD_PER_LUN)) 367262306a36Sopenharmony_ci pr_warn("cmd_per_lun = %d > queue_size = %d\n", 367362306a36Sopenharmony_ci target->scsi_host->cmd_per_lun, 367462306a36Sopenharmony_ci target->scsi_host->can_queue); 367562306a36Sopenharmony_ci 367662306a36Sopenharmony_ciout: 367762306a36Sopenharmony_ci kfree(options); 367862306a36Sopenharmony_ci return ret; 367962306a36Sopenharmony_ci} 368062306a36Sopenharmony_ci 368162306a36Sopenharmony_cistatic ssize_t add_target_store(struct device *dev, 368262306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, 368362306a36Sopenharmony_ci size_t count) 368462306a36Sopenharmony_ci{ 368562306a36Sopenharmony_ci struct srp_host *host = 368662306a36Sopenharmony_ci container_of(dev, struct srp_host, dev); 368762306a36Sopenharmony_ci struct Scsi_Host *target_host; 368862306a36Sopenharmony_ci struct srp_target_port *target; 368962306a36Sopenharmony_ci struct srp_rdma_ch *ch; 369062306a36Sopenharmony_ci struct srp_device *srp_dev = host->srp_dev; 369162306a36Sopenharmony_ci struct ib_device *ibdev = srp_dev->dev; 369262306a36Sopenharmony_ci int ret, i, ch_idx; 369362306a36Sopenharmony_ci unsigned int max_sectors_per_mr, mr_per_cmd = 0; 369462306a36Sopenharmony_ci bool multich = false; 369562306a36Sopenharmony_ci uint32_t max_iu_len; 369662306a36Sopenharmony_ci 369762306a36Sopenharmony_ci target_host = scsi_host_alloc(&srp_template, 369862306a36Sopenharmony_ci sizeof (struct srp_target_port)); 369962306a36Sopenharmony_ci if (!target_host) 370062306a36Sopenharmony_ci return -ENOMEM; 370162306a36Sopenharmony_ci 370262306a36Sopenharmony_ci target_host->transportt = ib_srp_transport_template; 370362306a36Sopenharmony_ci target_host->max_channel = 0; 370462306a36Sopenharmony_ci target_host->max_id = 1; 370562306a36Sopenharmony_ci target_host->max_lun = -1LL; 370662306a36Sopenharmony_ci target_host->max_cmd_len = sizeof ((struct srp_cmd *) (void *) 0L)->cdb; 370762306a36Sopenharmony_ci target_host->max_segment_size = ib_dma_max_seg_size(ibdev); 370862306a36Sopenharmony_ci 370962306a36Sopenharmony_ci if (!(ibdev->attrs.kernel_cap_flags & IBK_SG_GAPS_REG)) 371062306a36Sopenharmony_ci target_host->virt_boundary_mask = ~srp_dev->mr_page_mask; 371162306a36Sopenharmony_ci 371262306a36Sopenharmony_ci target = host_to_target(target_host); 371362306a36Sopenharmony_ci 371462306a36Sopenharmony_ci target->net = kobj_ns_grab_current(KOBJ_NS_TYPE_NET); 371562306a36Sopenharmony_ci target->io_class = SRP_REV16A_IB_IO_CLASS; 371662306a36Sopenharmony_ci target->scsi_host = target_host; 371762306a36Sopenharmony_ci target->srp_host = host; 371862306a36Sopenharmony_ci target->lkey = host->srp_dev->pd->local_dma_lkey; 371962306a36Sopenharmony_ci target->global_rkey = host->srp_dev->global_rkey; 372062306a36Sopenharmony_ci target->cmd_sg_cnt = cmd_sg_entries; 372162306a36Sopenharmony_ci target->sg_tablesize = indirect_sg_entries ? : cmd_sg_entries; 372262306a36Sopenharmony_ci target->allow_ext_sg = allow_ext_sg; 372362306a36Sopenharmony_ci target->tl_retry_count = 7; 372462306a36Sopenharmony_ci target->queue_size = SRP_DEFAULT_QUEUE_SIZE; 372562306a36Sopenharmony_ci 372662306a36Sopenharmony_ci /* 372762306a36Sopenharmony_ci * Avoid that the SCSI host can be removed by srp_remove_target() 372862306a36Sopenharmony_ci * before this function returns. 372962306a36Sopenharmony_ci */ 373062306a36Sopenharmony_ci scsi_host_get(target->scsi_host); 373162306a36Sopenharmony_ci 373262306a36Sopenharmony_ci ret = mutex_lock_interruptible(&host->add_target_mutex); 373362306a36Sopenharmony_ci if (ret < 0) 373462306a36Sopenharmony_ci goto put; 373562306a36Sopenharmony_ci 373662306a36Sopenharmony_ci ret = srp_parse_options(target->net, buf, target); 373762306a36Sopenharmony_ci if (ret) 373862306a36Sopenharmony_ci goto out; 373962306a36Sopenharmony_ci 374062306a36Sopenharmony_ci if (!srp_conn_unique(target->srp_host, target)) { 374162306a36Sopenharmony_ci if (target->using_rdma_cm) { 374262306a36Sopenharmony_ci shost_printk(KERN_INFO, target->scsi_host, 374362306a36Sopenharmony_ci PFX "Already connected to target port with id_ext=%016llx;ioc_guid=%016llx;dest=%pIS\n", 374462306a36Sopenharmony_ci be64_to_cpu(target->id_ext), 374562306a36Sopenharmony_ci be64_to_cpu(target->ioc_guid), 374662306a36Sopenharmony_ci &target->rdma_cm.dst); 374762306a36Sopenharmony_ci } else { 374862306a36Sopenharmony_ci shost_printk(KERN_INFO, target->scsi_host, 374962306a36Sopenharmony_ci PFX "Already connected to target port with id_ext=%016llx;ioc_guid=%016llx;initiator_ext=%016llx\n", 375062306a36Sopenharmony_ci be64_to_cpu(target->id_ext), 375162306a36Sopenharmony_ci be64_to_cpu(target->ioc_guid), 375262306a36Sopenharmony_ci be64_to_cpu(target->initiator_ext)); 375362306a36Sopenharmony_ci } 375462306a36Sopenharmony_ci ret = -EEXIST; 375562306a36Sopenharmony_ci goto out; 375662306a36Sopenharmony_ci } 375762306a36Sopenharmony_ci 375862306a36Sopenharmony_ci if (!srp_dev->has_fr && !target->allow_ext_sg && 375962306a36Sopenharmony_ci target->cmd_sg_cnt < target->sg_tablesize) { 376062306a36Sopenharmony_ci pr_warn("No MR pool and no external indirect descriptors, limiting sg_tablesize to cmd_sg_cnt\n"); 376162306a36Sopenharmony_ci target->sg_tablesize = target->cmd_sg_cnt; 376262306a36Sopenharmony_ci } 376362306a36Sopenharmony_ci 376462306a36Sopenharmony_ci if (srp_dev->use_fast_reg) { 376562306a36Sopenharmony_ci bool gaps_reg = ibdev->attrs.kernel_cap_flags & 376662306a36Sopenharmony_ci IBK_SG_GAPS_REG; 376762306a36Sopenharmony_ci 376862306a36Sopenharmony_ci max_sectors_per_mr = srp_dev->max_pages_per_mr << 376962306a36Sopenharmony_ci (ilog2(srp_dev->mr_page_size) - 9); 377062306a36Sopenharmony_ci if (!gaps_reg) { 377162306a36Sopenharmony_ci /* 377262306a36Sopenharmony_ci * FR can only map one HCA page per entry. If the start 377362306a36Sopenharmony_ci * address is not aligned on a HCA page boundary two 377462306a36Sopenharmony_ci * entries will be used for the head and the tail 377562306a36Sopenharmony_ci * although these two entries combined contain at most 377662306a36Sopenharmony_ci * one HCA page of data. Hence the "+ 1" in the 377762306a36Sopenharmony_ci * calculation below. 377862306a36Sopenharmony_ci * 377962306a36Sopenharmony_ci * The indirect data buffer descriptor is contiguous 378062306a36Sopenharmony_ci * so the memory for that buffer will only be 378162306a36Sopenharmony_ci * registered if register_always is true. Hence add 378262306a36Sopenharmony_ci * one to mr_per_cmd if register_always has been set. 378362306a36Sopenharmony_ci */ 378462306a36Sopenharmony_ci mr_per_cmd = register_always + 378562306a36Sopenharmony_ci (target->scsi_host->max_sectors + 1 + 378662306a36Sopenharmony_ci max_sectors_per_mr - 1) / max_sectors_per_mr; 378762306a36Sopenharmony_ci } else { 378862306a36Sopenharmony_ci mr_per_cmd = register_always + 378962306a36Sopenharmony_ci (target->sg_tablesize + 379062306a36Sopenharmony_ci srp_dev->max_pages_per_mr - 1) / 379162306a36Sopenharmony_ci srp_dev->max_pages_per_mr; 379262306a36Sopenharmony_ci } 379362306a36Sopenharmony_ci pr_debug("max_sectors = %u; max_pages_per_mr = %u; mr_page_size = %u; max_sectors_per_mr = %u; mr_per_cmd = %u\n", 379462306a36Sopenharmony_ci target->scsi_host->max_sectors, srp_dev->max_pages_per_mr, srp_dev->mr_page_size, 379562306a36Sopenharmony_ci max_sectors_per_mr, mr_per_cmd); 379662306a36Sopenharmony_ci } 379762306a36Sopenharmony_ci 379862306a36Sopenharmony_ci target_host->sg_tablesize = target->sg_tablesize; 379962306a36Sopenharmony_ci target->mr_pool_size = target->scsi_host->can_queue * mr_per_cmd; 380062306a36Sopenharmony_ci target->mr_per_cmd = mr_per_cmd; 380162306a36Sopenharmony_ci target->indirect_size = target->sg_tablesize * 380262306a36Sopenharmony_ci sizeof (struct srp_direct_buf); 380362306a36Sopenharmony_ci max_iu_len = srp_max_it_iu_len(target->cmd_sg_cnt, 380462306a36Sopenharmony_ci srp_use_imm_data, 380562306a36Sopenharmony_ci target->max_it_iu_size); 380662306a36Sopenharmony_ci 380762306a36Sopenharmony_ci INIT_WORK(&target->tl_err_work, srp_tl_err_work); 380862306a36Sopenharmony_ci INIT_WORK(&target->remove_work, srp_remove_work); 380962306a36Sopenharmony_ci spin_lock_init(&target->lock); 381062306a36Sopenharmony_ci ret = rdma_query_gid(ibdev, host->port, 0, &target->sgid); 381162306a36Sopenharmony_ci if (ret) 381262306a36Sopenharmony_ci goto out; 381362306a36Sopenharmony_ci 381462306a36Sopenharmony_ci ret = -ENOMEM; 381562306a36Sopenharmony_ci if (target->ch_count == 0) { 381662306a36Sopenharmony_ci target->ch_count = 381762306a36Sopenharmony_ci min(ch_count ?: 381862306a36Sopenharmony_ci max(4 * num_online_nodes(), 381962306a36Sopenharmony_ci ibdev->num_comp_vectors), 382062306a36Sopenharmony_ci num_online_cpus()); 382162306a36Sopenharmony_ci } 382262306a36Sopenharmony_ci 382362306a36Sopenharmony_ci target->ch = kcalloc(target->ch_count, sizeof(*target->ch), 382462306a36Sopenharmony_ci GFP_KERNEL); 382562306a36Sopenharmony_ci if (!target->ch) 382662306a36Sopenharmony_ci goto out; 382762306a36Sopenharmony_ci 382862306a36Sopenharmony_ci for (ch_idx = 0; ch_idx < target->ch_count; ++ch_idx) { 382962306a36Sopenharmony_ci ch = &target->ch[ch_idx]; 383062306a36Sopenharmony_ci ch->target = target; 383162306a36Sopenharmony_ci ch->comp_vector = ch_idx % ibdev->num_comp_vectors; 383262306a36Sopenharmony_ci spin_lock_init(&ch->lock); 383362306a36Sopenharmony_ci INIT_LIST_HEAD(&ch->free_tx); 383462306a36Sopenharmony_ci ret = srp_new_cm_id(ch); 383562306a36Sopenharmony_ci if (ret) 383662306a36Sopenharmony_ci goto err_disconnect; 383762306a36Sopenharmony_ci 383862306a36Sopenharmony_ci ret = srp_create_ch_ib(ch); 383962306a36Sopenharmony_ci if (ret) 384062306a36Sopenharmony_ci goto err_disconnect; 384162306a36Sopenharmony_ci 384262306a36Sopenharmony_ci ret = srp_connect_ch(ch, max_iu_len, multich); 384362306a36Sopenharmony_ci if (ret) { 384462306a36Sopenharmony_ci char dst[64]; 384562306a36Sopenharmony_ci 384662306a36Sopenharmony_ci if (target->using_rdma_cm) 384762306a36Sopenharmony_ci snprintf(dst, sizeof(dst), "%pIS", 384862306a36Sopenharmony_ci &target->rdma_cm.dst); 384962306a36Sopenharmony_ci else 385062306a36Sopenharmony_ci snprintf(dst, sizeof(dst), "%pI6", 385162306a36Sopenharmony_ci target->ib_cm.orig_dgid.raw); 385262306a36Sopenharmony_ci shost_printk(KERN_ERR, target->scsi_host, 385362306a36Sopenharmony_ci PFX "Connection %d/%d to %s failed\n", 385462306a36Sopenharmony_ci ch_idx, 385562306a36Sopenharmony_ci target->ch_count, dst); 385662306a36Sopenharmony_ci if (ch_idx == 0) { 385762306a36Sopenharmony_ci goto free_ch; 385862306a36Sopenharmony_ci } else { 385962306a36Sopenharmony_ci srp_free_ch_ib(target, ch); 386062306a36Sopenharmony_ci target->ch_count = ch - target->ch; 386162306a36Sopenharmony_ci goto connected; 386262306a36Sopenharmony_ci } 386362306a36Sopenharmony_ci } 386462306a36Sopenharmony_ci multich = true; 386562306a36Sopenharmony_ci } 386662306a36Sopenharmony_ci 386762306a36Sopenharmony_ciconnected: 386862306a36Sopenharmony_ci target->scsi_host->nr_hw_queues = target->ch_count; 386962306a36Sopenharmony_ci 387062306a36Sopenharmony_ci ret = srp_add_target(host, target); 387162306a36Sopenharmony_ci if (ret) 387262306a36Sopenharmony_ci goto err_disconnect; 387362306a36Sopenharmony_ci 387462306a36Sopenharmony_ci if (target->state != SRP_TARGET_REMOVED) { 387562306a36Sopenharmony_ci if (target->using_rdma_cm) { 387662306a36Sopenharmony_ci shost_printk(KERN_DEBUG, target->scsi_host, PFX 387762306a36Sopenharmony_ci "new target: id_ext %016llx ioc_guid %016llx sgid %pI6 dest %pIS\n", 387862306a36Sopenharmony_ci be64_to_cpu(target->id_ext), 387962306a36Sopenharmony_ci be64_to_cpu(target->ioc_guid), 388062306a36Sopenharmony_ci target->sgid.raw, &target->rdma_cm.dst); 388162306a36Sopenharmony_ci } else { 388262306a36Sopenharmony_ci shost_printk(KERN_DEBUG, target->scsi_host, PFX 388362306a36Sopenharmony_ci "new target: id_ext %016llx ioc_guid %016llx pkey %04x service_id %016llx sgid %pI6 dgid %pI6\n", 388462306a36Sopenharmony_ci be64_to_cpu(target->id_ext), 388562306a36Sopenharmony_ci be64_to_cpu(target->ioc_guid), 388662306a36Sopenharmony_ci be16_to_cpu(target->ib_cm.pkey), 388762306a36Sopenharmony_ci be64_to_cpu(target->ib_cm.service_id), 388862306a36Sopenharmony_ci target->sgid.raw, 388962306a36Sopenharmony_ci target->ib_cm.orig_dgid.raw); 389062306a36Sopenharmony_ci } 389162306a36Sopenharmony_ci } 389262306a36Sopenharmony_ci 389362306a36Sopenharmony_ci ret = count; 389462306a36Sopenharmony_ci 389562306a36Sopenharmony_ciout: 389662306a36Sopenharmony_ci mutex_unlock(&host->add_target_mutex); 389762306a36Sopenharmony_ci 389862306a36Sopenharmony_ciput: 389962306a36Sopenharmony_ci scsi_host_put(target->scsi_host); 390062306a36Sopenharmony_ci if (ret < 0) { 390162306a36Sopenharmony_ci /* 390262306a36Sopenharmony_ci * If a call to srp_remove_target() has not been scheduled, 390362306a36Sopenharmony_ci * drop the network namespace reference now that was obtained 390462306a36Sopenharmony_ci * earlier in this function. 390562306a36Sopenharmony_ci */ 390662306a36Sopenharmony_ci if (target->state != SRP_TARGET_REMOVED) 390762306a36Sopenharmony_ci kobj_ns_drop(KOBJ_NS_TYPE_NET, target->net); 390862306a36Sopenharmony_ci scsi_host_put(target->scsi_host); 390962306a36Sopenharmony_ci } 391062306a36Sopenharmony_ci 391162306a36Sopenharmony_ci return ret; 391262306a36Sopenharmony_ci 391362306a36Sopenharmony_cierr_disconnect: 391462306a36Sopenharmony_ci srp_disconnect_target(target); 391562306a36Sopenharmony_ci 391662306a36Sopenharmony_cifree_ch: 391762306a36Sopenharmony_ci for (i = 0; i < target->ch_count; i++) { 391862306a36Sopenharmony_ci ch = &target->ch[i]; 391962306a36Sopenharmony_ci srp_free_ch_ib(target, ch); 392062306a36Sopenharmony_ci } 392162306a36Sopenharmony_ci 392262306a36Sopenharmony_ci kfree(target->ch); 392362306a36Sopenharmony_ci goto out; 392462306a36Sopenharmony_ci} 392562306a36Sopenharmony_ci 392662306a36Sopenharmony_cistatic DEVICE_ATTR_WO(add_target); 392762306a36Sopenharmony_ci 392862306a36Sopenharmony_cistatic ssize_t ibdev_show(struct device *dev, struct device_attribute *attr, 392962306a36Sopenharmony_ci char *buf) 393062306a36Sopenharmony_ci{ 393162306a36Sopenharmony_ci struct srp_host *host = container_of(dev, struct srp_host, dev); 393262306a36Sopenharmony_ci 393362306a36Sopenharmony_ci return sysfs_emit(buf, "%s\n", dev_name(&host->srp_dev->dev->dev)); 393462306a36Sopenharmony_ci} 393562306a36Sopenharmony_ci 393662306a36Sopenharmony_cistatic DEVICE_ATTR_RO(ibdev); 393762306a36Sopenharmony_ci 393862306a36Sopenharmony_cistatic ssize_t port_show(struct device *dev, struct device_attribute *attr, 393962306a36Sopenharmony_ci char *buf) 394062306a36Sopenharmony_ci{ 394162306a36Sopenharmony_ci struct srp_host *host = container_of(dev, struct srp_host, dev); 394262306a36Sopenharmony_ci 394362306a36Sopenharmony_ci return sysfs_emit(buf, "%u\n", host->port); 394462306a36Sopenharmony_ci} 394562306a36Sopenharmony_ci 394662306a36Sopenharmony_cistatic DEVICE_ATTR_RO(port); 394762306a36Sopenharmony_ci 394862306a36Sopenharmony_cistatic struct attribute *srp_class_attrs[] = { 394962306a36Sopenharmony_ci &dev_attr_add_target.attr, 395062306a36Sopenharmony_ci &dev_attr_ibdev.attr, 395162306a36Sopenharmony_ci &dev_attr_port.attr, 395262306a36Sopenharmony_ci NULL 395362306a36Sopenharmony_ci}; 395462306a36Sopenharmony_ci 395562306a36Sopenharmony_cistatic struct srp_host *srp_add_port(struct srp_device *device, u32 port) 395662306a36Sopenharmony_ci{ 395762306a36Sopenharmony_ci struct srp_host *host; 395862306a36Sopenharmony_ci 395962306a36Sopenharmony_ci host = kzalloc(sizeof *host, GFP_KERNEL); 396062306a36Sopenharmony_ci if (!host) 396162306a36Sopenharmony_ci return NULL; 396262306a36Sopenharmony_ci 396362306a36Sopenharmony_ci INIT_LIST_HEAD(&host->target_list); 396462306a36Sopenharmony_ci spin_lock_init(&host->target_lock); 396562306a36Sopenharmony_ci mutex_init(&host->add_target_mutex); 396662306a36Sopenharmony_ci host->srp_dev = device; 396762306a36Sopenharmony_ci host->port = port; 396862306a36Sopenharmony_ci 396962306a36Sopenharmony_ci device_initialize(&host->dev); 397062306a36Sopenharmony_ci host->dev.class = &srp_class; 397162306a36Sopenharmony_ci host->dev.parent = device->dev->dev.parent; 397262306a36Sopenharmony_ci if (dev_set_name(&host->dev, "srp-%s-%u", dev_name(&device->dev->dev), 397362306a36Sopenharmony_ci port)) 397462306a36Sopenharmony_ci goto put_host; 397562306a36Sopenharmony_ci if (device_add(&host->dev)) 397662306a36Sopenharmony_ci goto put_host; 397762306a36Sopenharmony_ci 397862306a36Sopenharmony_ci return host; 397962306a36Sopenharmony_ci 398062306a36Sopenharmony_ciput_host: 398162306a36Sopenharmony_ci device_del(&host->dev); 398262306a36Sopenharmony_ci put_device(&host->dev); 398362306a36Sopenharmony_ci return NULL; 398462306a36Sopenharmony_ci} 398562306a36Sopenharmony_ci 398662306a36Sopenharmony_cistatic void srp_rename_dev(struct ib_device *device, void *client_data) 398762306a36Sopenharmony_ci{ 398862306a36Sopenharmony_ci struct srp_device *srp_dev = client_data; 398962306a36Sopenharmony_ci struct srp_host *host, *tmp_host; 399062306a36Sopenharmony_ci 399162306a36Sopenharmony_ci list_for_each_entry_safe(host, tmp_host, &srp_dev->dev_list, list) { 399262306a36Sopenharmony_ci char name[IB_DEVICE_NAME_MAX + 8]; 399362306a36Sopenharmony_ci 399462306a36Sopenharmony_ci snprintf(name, sizeof(name), "srp-%s-%u", 399562306a36Sopenharmony_ci dev_name(&device->dev), host->port); 399662306a36Sopenharmony_ci device_rename(&host->dev, name); 399762306a36Sopenharmony_ci } 399862306a36Sopenharmony_ci} 399962306a36Sopenharmony_ci 400062306a36Sopenharmony_cistatic int srp_add_one(struct ib_device *device) 400162306a36Sopenharmony_ci{ 400262306a36Sopenharmony_ci struct srp_device *srp_dev; 400362306a36Sopenharmony_ci struct ib_device_attr *attr = &device->attrs; 400462306a36Sopenharmony_ci struct srp_host *host; 400562306a36Sopenharmony_ci int mr_page_shift; 400662306a36Sopenharmony_ci u32 p; 400762306a36Sopenharmony_ci u64 max_pages_per_mr; 400862306a36Sopenharmony_ci unsigned int flags = 0; 400962306a36Sopenharmony_ci 401062306a36Sopenharmony_ci srp_dev = kzalloc(sizeof(*srp_dev), GFP_KERNEL); 401162306a36Sopenharmony_ci if (!srp_dev) 401262306a36Sopenharmony_ci return -ENOMEM; 401362306a36Sopenharmony_ci 401462306a36Sopenharmony_ci /* 401562306a36Sopenharmony_ci * Use the smallest page size supported by the HCA, down to a 401662306a36Sopenharmony_ci * minimum of 4096 bytes. We're unlikely to build large sglists 401762306a36Sopenharmony_ci * out of smaller entries. 401862306a36Sopenharmony_ci */ 401962306a36Sopenharmony_ci mr_page_shift = max(12, ffs(attr->page_size_cap) - 1); 402062306a36Sopenharmony_ci srp_dev->mr_page_size = 1 << mr_page_shift; 402162306a36Sopenharmony_ci srp_dev->mr_page_mask = ~((u64) srp_dev->mr_page_size - 1); 402262306a36Sopenharmony_ci max_pages_per_mr = attr->max_mr_size; 402362306a36Sopenharmony_ci do_div(max_pages_per_mr, srp_dev->mr_page_size); 402462306a36Sopenharmony_ci pr_debug("%s: %llu / %u = %llu <> %u\n", __func__, 402562306a36Sopenharmony_ci attr->max_mr_size, srp_dev->mr_page_size, 402662306a36Sopenharmony_ci max_pages_per_mr, SRP_MAX_PAGES_PER_MR); 402762306a36Sopenharmony_ci srp_dev->max_pages_per_mr = min_t(u64, SRP_MAX_PAGES_PER_MR, 402862306a36Sopenharmony_ci max_pages_per_mr); 402962306a36Sopenharmony_ci 403062306a36Sopenharmony_ci srp_dev->has_fr = (attr->device_cap_flags & 403162306a36Sopenharmony_ci IB_DEVICE_MEM_MGT_EXTENSIONS); 403262306a36Sopenharmony_ci if (!never_register && !srp_dev->has_fr) 403362306a36Sopenharmony_ci dev_warn(&device->dev, "FR is not supported\n"); 403462306a36Sopenharmony_ci else if (!never_register && 403562306a36Sopenharmony_ci attr->max_mr_size >= 2 * srp_dev->mr_page_size) 403662306a36Sopenharmony_ci srp_dev->use_fast_reg = srp_dev->has_fr; 403762306a36Sopenharmony_ci 403862306a36Sopenharmony_ci if (never_register || !register_always || !srp_dev->has_fr) 403962306a36Sopenharmony_ci flags |= IB_PD_UNSAFE_GLOBAL_RKEY; 404062306a36Sopenharmony_ci 404162306a36Sopenharmony_ci if (srp_dev->use_fast_reg) { 404262306a36Sopenharmony_ci srp_dev->max_pages_per_mr = 404362306a36Sopenharmony_ci min_t(u32, srp_dev->max_pages_per_mr, 404462306a36Sopenharmony_ci attr->max_fast_reg_page_list_len); 404562306a36Sopenharmony_ci } 404662306a36Sopenharmony_ci srp_dev->mr_max_size = srp_dev->mr_page_size * 404762306a36Sopenharmony_ci srp_dev->max_pages_per_mr; 404862306a36Sopenharmony_ci pr_debug("%s: mr_page_shift = %d, device->max_mr_size = %#llx, device->max_fast_reg_page_list_len = %u, max_pages_per_mr = %d, mr_max_size = %#x\n", 404962306a36Sopenharmony_ci dev_name(&device->dev), mr_page_shift, attr->max_mr_size, 405062306a36Sopenharmony_ci attr->max_fast_reg_page_list_len, 405162306a36Sopenharmony_ci srp_dev->max_pages_per_mr, srp_dev->mr_max_size); 405262306a36Sopenharmony_ci 405362306a36Sopenharmony_ci INIT_LIST_HEAD(&srp_dev->dev_list); 405462306a36Sopenharmony_ci 405562306a36Sopenharmony_ci srp_dev->dev = device; 405662306a36Sopenharmony_ci srp_dev->pd = ib_alloc_pd(device, flags); 405762306a36Sopenharmony_ci if (IS_ERR(srp_dev->pd)) { 405862306a36Sopenharmony_ci int ret = PTR_ERR(srp_dev->pd); 405962306a36Sopenharmony_ci 406062306a36Sopenharmony_ci kfree(srp_dev); 406162306a36Sopenharmony_ci return ret; 406262306a36Sopenharmony_ci } 406362306a36Sopenharmony_ci 406462306a36Sopenharmony_ci if (flags & IB_PD_UNSAFE_GLOBAL_RKEY) { 406562306a36Sopenharmony_ci srp_dev->global_rkey = srp_dev->pd->unsafe_global_rkey; 406662306a36Sopenharmony_ci WARN_ON_ONCE(srp_dev->global_rkey == 0); 406762306a36Sopenharmony_ci } 406862306a36Sopenharmony_ci 406962306a36Sopenharmony_ci rdma_for_each_port (device, p) { 407062306a36Sopenharmony_ci host = srp_add_port(srp_dev, p); 407162306a36Sopenharmony_ci if (host) 407262306a36Sopenharmony_ci list_add_tail(&host->list, &srp_dev->dev_list); 407362306a36Sopenharmony_ci } 407462306a36Sopenharmony_ci 407562306a36Sopenharmony_ci ib_set_client_data(device, &srp_client, srp_dev); 407662306a36Sopenharmony_ci return 0; 407762306a36Sopenharmony_ci} 407862306a36Sopenharmony_ci 407962306a36Sopenharmony_cistatic void srp_remove_one(struct ib_device *device, void *client_data) 408062306a36Sopenharmony_ci{ 408162306a36Sopenharmony_ci struct srp_device *srp_dev; 408262306a36Sopenharmony_ci struct srp_host *host, *tmp_host; 408362306a36Sopenharmony_ci struct srp_target_port *target; 408462306a36Sopenharmony_ci 408562306a36Sopenharmony_ci srp_dev = client_data; 408662306a36Sopenharmony_ci 408762306a36Sopenharmony_ci list_for_each_entry_safe(host, tmp_host, &srp_dev->dev_list, list) { 408862306a36Sopenharmony_ci /* 408962306a36Sopenharmony_ci * Remove the add_target sysfs entry so that no new target ports 409062306a36Sopenharmony_ci * can be created. 409162306a36Sopenharmony_ci */ 409262306a36Sopenharmony_ci device_del(&host->dev); 409362306a36Sopenharmony_ci 409462306a36Sopenharmony_ci /* 409562306a36Sopenharmony_ci * Remove all target ports. 409662306a36Sopenharmony_ci */ 409762306a36Sopenharmony_ci spin_lock(&host->target_lock); 409862306a36Sopenharmony_ci list_for_each_entry(target, &host->target_list, list) 409962306a36Sopenharmony_ci srp_queue_remove_work(target); 410062306a36Sopenharmony_ci spin_unlock(&host->target_lock); 410162306a36Sopenharmony_ci 410262306a36Sopenharmony_ci /* 410362306a36Sopenharmony_ci * srp_queue_remove_work() queues a call to 410462306a36Sopenharmony_ci * srp_remove_target(). The latter function cancels 410562306a36Sopenharmony_ci * target->tl_err_work so waiting for the remove works to 410662306a36Sopenharmony_ci * finish is sufficient. 410762306a36Sopenharmony_ci */ 410862306a36Sopenharmony_ci flush_workqueue(srp_remove_wq); 410962306a36Sopenharmony_ci 411062306a36Sopenharmony_ci put_device(&host->dev); 411162306a36Sopenharmony_ci } 411262306a36Sopenharmony_ci 411362306a36Sopenharmony_ci ib_dealloc_pd(srp_dev->pd); 411462306a36Sopenharmony_ci 411562306a36Sopenharmony_ci kfree(srp_dev); 411662306a36Sopenharmony_ci} 411762306a36Sopenharmony_ci 411862306a36Sopenharmony_cistatic struct srp_function_template ib_srp_transport_functions = { 411962306a36Sopenharmony_ci .has_rport_state = true, 412062306a36Sopenharmony_ci .reset_timer_if_blocked = true, 412162306a36Sopenharmony_ci .reconnect_delay = &srp_reconnect_delay, 412262306a36Sopenharmony_ci .fast_io_fail_tmo = &srp_fast_io_fail_tmo, 412362306a36Sopenharmony_ci .dev_loss_tmo = &srp_dev_loss_tmo, 412462306a36Sopenharmony_ci .reconnect = srp_rport_reconnect, 412562306a36Sopenharmony_ci .rport_delete = srp_rport_delete, 412662306a36Sopenharmony_ci .terminate_rport_io = srp_terminate_io, 412762306a36Sopenharmony_ci}; 412862306a36Sopenharmony_ci 412962306a36Sopenharmony_cistatic int __init srp_init_module(void) 413062306a36Sopenharmony_ci{ 413162306a36Sopenharmony_ci int ret; 413262306a36Sopenharmony_ci 413362306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct srp_aer_req) != 36); 413462306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct srp_cmd) != 48); 413562306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct srp_imm_buf) != 4); 413662306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct srp_indirect_buf) != 20); 413762306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct srp_login_req) != 64); 413862306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct srp_login_req_rdma) != 56); 413962306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct srp_rsp) != 36); 414062306a36Sopenharmony_ci 414162306a36Sopenharmony_ci if (srp_sg_tablesize) { 414262306a36Sopenharmony_ci pr_warn("srp_sg_tablesize is deprecated, please use cmd_sg_entries\n"); 414362306a36Sopenharmony_ci if (!cmd_sg_entries) 414462306a36Sopenharmony_ci cmd_sg_entries = srp_sg_tablesize; 414562306a36Sopenharmony_ci } 414662306a36Sopenharmony_ci 414762306a36Sopenharmony_ci if (!cmd_sg_entries) 414862306a36Sopenharmony_ci cmd_sg_entries = SRP_DEF_SG_TABLESIZE; 414962306a36Sopenharmony_ci 415062306a36Sopenharmony_ci if (cmd_sg_entries > 255) { 415162306a36Sopenharmony_ci pr_warn("Clamping cmd_sg_entries to 255\n"); 415262306a36Sopenharmony_ci cmd_sg_entries = 255; 415362306a36Sopenharmony_ci } 415462306a36Sopenharmony_ci 415562306a36Sopenharmony_ci if (!indirect_sg_entries) 415662306a36Sopenharmony_ci indirect_sg_entries = cmd_sg_entries; 415762306a36Sopenharmony_ci else if (indirect_sg_entries < cmd_sg_entries) { 415862306a36Sopenharmony_ci pr_warn("Bumping up indirect_sg_entries to match cmd_sg_entries (%u)\n", 415962306a36Sopenharmony_ci cmd_sg_entries); 416062306a36Sopenharmony_ci indirect_sg_entries = cmd_sg_entries; 416162306a36Sopenharmony_ci } 416262306a36Sopenharmony_ci 416362306a36Sopenharmony_ci if (indirect_sg_entries > SG_MAX_SEGMENTS) { 416462306a36Sopenharmony_ci pr_warn("Clamping indirect_sg_entries to %u\n", 416562306a36Sopenharmony_ci SG_MAX_SEGMENTS); 416662306a36Sopenharmony_ci indirect_sg_entries = SG_MAX_SEGMENTS; 416762306a36Sopenharmony_ci } 416862306a36Sopenharmony_ci 416962306a36Sopenharmony_ci srp_remove_wq = create_workqueue("srp_remove"); 417062306a36Sopenharmony_ci if (!srp_remove_wq) { 417162306a36Sopenharmony_ci ret = -ENOMEM; 417262306a36Sopenharmony_ci goto out; 417362306a36Sopenharmony_ci } 417462306a36Sopenharmony_ci 417562306a36Sopenharmony_ci ret = -ENOMEM; 417662306a36Sopenharmony_ci ib_srp_transport_template = 417762306a36Sopenharmony_ci srp_attach_transport(&ib_srp_transport_functions); 417862306a36Sopenharmony_ci if (!ib_srp_transport_template) 417962306a36Sopenharmony_ci goto destroy_wq; 418062306a36Sopenharmony_ci 418162306a36Sopenharmony_ci ret = class_register(&srp_class); 418262306a36Sopenharmony_ci if (ret) { 418362306a36Sopenharmony_ci pr_err("couldn't register class infiniband_srp\n"); 418462306a36Sopenharmony_ci goto release_tr; 418562306a36Sopenharmony_ci } 418662306a36Sopenharmony_ci 418762306a36Sopenharmony_ci ib_sa_register_client(&srp_sa_client); 418862306a36Sopenharmony_ci 418962306a36Sopenharmony_ci ret = ib_register_client(&srp_client); 419062306a36Sopenharmony_ci if (ret) { 419162306a36Sopenharmony_ci pr_err("couldn't register IB client\n"); 419262306a36Sopenharmony_ci goto unreg_sa; 419362306a36Sopenharmony_ci } 419462306a36Sopenharmony_ci 419562306a36Sopenharmony_ciout: 419662306a36Sopenharmony_ci return ret; 419762306a36Sopenharmony_ci 419862306a36Sopenharmony_ciunreg_sa: 419962306a36Sopenharmony_ci ib_sa_unregister_client(&srp_sa_client); 420062306a36Sopenharmony_ci class_unregister(&srp_class); 420162306a36Sopenharmony_ci 420262306a36Sopenharmony_cirelease_tr: 420362306a36Sopenharmony_ci srp_release_transport(ib_srp_transport_template); 420462306a36Sopenharmony_ci 420562306a36Sopenharmony_cidestroy_wq: 420662306a36Sopenharmony_ci destroy_workqueue(srp_remove_wq); 420762306a36Sopenharmony_ci goto out; 420862306a36Sopenharmony_ci} 420962306a36Sopenharmony_ci 421062306a36Sopenharmony_cistatic void __exit srp_cleanup_module(void) 421162306a36Sopenharmony_ci{ 421262306a36Sopenharmony_ci ib_unregister_client(&srp_client); 421362306a36Sopenharmony_ci ib_sa_unregister_client(&srp_sa_client); 421462306a36Sopenharmony_ci class_unregister(&srp_class); 421562306a36Sopenharmony_ci srp_release_transport(ib_srp_transport_template); 421662306a36Sopenharmony_ci destroy_workqueue(srp_remove_wq); 421762306a36Sopenharmony_ci} 421862306a36Sopenharmony_ci 421962306a36Sopenharmony_cimodule_init(srp_init_module); 422062306a36Sopenharmony_cimodule_exit(srp_cleanup_module); 4221