1aef9ec39SRoland Dreier /*
2aef9ec39SRoland Dreier * Copyright (c) 2005 Cisco Systems. All rights reserved.
3aef9ec39SRoland Dreier *
4aef9ec39SRoland Dreier * This software is available to you under a choice of one of two
5aef9ec39SRoland Dreier * licenses. You may choose to be licensed under the terms of the GNU
6aef9ec39SRoland Dreier * General Public License (GPL) Version 2, available from the file
7aef9ec39SRoland Dreier * COPYING in the main directory of this source tree, or the
8aef9ec39SRoland Dreier * OpenIB.org BSD license below:
9aef9ec39SRoland Dreier *
10aef9ec39SRoland Dreier * Redistribution and use in source and binary forms, with or
11aef9ec39SRoland Dreier * without modification, are permitted provided that the following
12aef9ec39SRoland Dreier * conditions are met:
13aef9ec39SRoland Dreier *
14aef9ec39SRoland Dreier * - Redistributions of source code must retain the above
15aef9ec39SRoland Dreier * copyright notice, this list of conditions and the following
16aef9ec39SRoland Dreier * disclaimer.
17aef9ec39SRoland Dreier *
18aef9ec39SRoland Dreier * - Redistributions in binary form must reproduce the above
19aef9ec39SRoland Dreier * copyright notice, this list of conditions and the following
20aef9ec39SRoland Dreier * disclaimer in the documentation and/or other materials
21aef9ec39SRoland Dreier * provided with the distribution.
22aef9ec39SRoland Dreier *
23aef9ec39SRoland Dreier * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24aef9ec39SRoland Dreier * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25aef9ec39SRoland Dreier * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26aef9ec39SRoland Dreier * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27aef9ec39SRoland Dreier * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28aef9ec39SRoland Dreier * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29aef9ec39SRoland Dreier * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30aef9ec39SRoland Dreier * SOFTWARE.
31aef9ec39SRoland Dreier */
32aef9ec39SRoland Dreier
33d236cd0eSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
34e0bda7d8SBart Van Assche
35aef9ec39SRoland Dreier #include <linux/module.h>
36aef9ec39SRoland Dreier #include <linux/init.h>
37aef9ec39SRoland Dreier #include <linux/slab.h>
38aef9ec39SRoland Dreier #include <linux/err.h>
39aef9ec39SRoland Dreier #include <linux/string.h>
40aef9ec39SRoland Dreier #include <linux/parser.h>
41aef9ec39SRoland Dreier #include <linux/random.h>
42de25968cSTim Schmielau #include <linux/jiffies.h>
4393c76dbbSBart Van Assche #include <linux/lockdep.h>
4419f31343SBart Van Assche #include <linux/inet.h>
4556b5390cSBart Van Assche #include <rdma/ib_cache.h>
46aef9ec39SRoland Dreier
4760063497SArun Sharma #include <linux/atomic.h>
48aef9ec39SRoland Dreier
49aef9ec39SRoland Dreier #include <scsi/scsi.h>
50aef9ec39SRoland Dreier #include <scsi/scsi_device.h>
51aef9ec39SRoland Dreier #include <scsi/scsi_dbg.h>
5271444b97SJack Wang #include <scsi/scsi_tcq.h>
53aef9ec39SRoland Dreier #include <scsi/srp.h>
543236822bSFUJITA Tomonori #include <scsi/scsi_transport_srp.h>
55aef9ec39SRoland Dreier
56aef9ec39SRoland Dreier #include "ib_srp.h"
57aef9ec39SRoland Dreier
58aef9ec39SRoland Dreier #define DRV_NAME "ib_srp"
59aef9ec39SRoland Dreier #define PFX DRV_NAME ": "
60aef9ec39SRoland Dreier
61aef9ec39SRoland Dreier MODULE_AUTHOR("Roland Dreier");
6233ab3e5bSBart Van Assche MODULE_DESCRIPTION("InfiniBand SCSI RDMA Protocol initiator");
63aef9ec39SRoland Dreier MODULE_LICENSE("Dual BSD/GPL");
64aef9ec39SRoland Dreier
6549248644SDavid Dillow static unsigned int srp_sg_tablesize;
6649248644SDavid Dillow static unsigned int cmd_sg_entries;
67c07d424dSDavid Dillow static unsigned int indirect_sg_entries;
68c07d424dSDavid Dillow static bool allow_ext_sg;
6903f6fb93SBart Van Assche static bool register_always = true;
70c222a39fSBart Van Assche static bool never_register;
71aef9ec39SRoland Dreier static int topspin_workarounds = 1;
72aef9ec39SRoland Dreier
7349248644SDavid Dillow module_param(srp_sg_tablesize, uint, 0444);
7449248644SDavid Dillow MODULE_PARM_DESC(srp_sg_tablesize, "Deprecated name for cmd_sg_entries");
7549248644SDavid Dillow
7649248644SDavid Dillow module_param(cmd_sg_entries, uint, 0444);
7749248644SDavid Dillow MODULE_PARM_DESC(cmd_sg_entries,
7849248644SDavid Dillow "Default number of gather/scatter entries in the SRP command (default is 12, max 255)");
7949248644SDavid Dillow
80c07d424dSDavid Dillow module_param(indirect_sg_entries, uint, 0444);
81c07d424dSDavid Dillow MODULE_PARM_DESC(indirect_sg_entries,
8265e8617fSMing Lin "Default max number of gather/scatter entries (default is 12, max is " __stringify(SG_MAX_SEGMENTS) ")");
83c07d424dSDavid Dillow
84c07d424dSDavid Dillow module_param(allow_ext_sg, bool, 0444);
85c07d424dSDavid Dillow MODULE_PARM_DESC(allow_ext_sg,
86c07d424dSDavid Dillow "Default behavior when there are more than cmd_sg_entries S/G entries after mapping; fails the request when false (default false)");
87c07d424dSDavid Dillow
88aef9ec39SRoland Dreier module_param(topspin_workarounds, int, 0444);
89aef9ec39SRoland Dreier MODULE_PARM_DESC(topspin_workarounds,
90aef9ec39SRoland Dreier "Enable workarounds for Topspin/Cisco SRP target bugs if != 0");
91aef9ec39SRoland Dreier
92b1b8854dSBart Van Assche module_param(register_always, bool, 0444);
93b1b8854dSBart Van Assche MODULE_PARM_DESC(register_always,
94b1b8854dSBart Van Assche "Use memory registration even for contiguous memory regions");
95b1b8854dSBart Van Assche
96c222a39fSBart Van Assche module_param(never_register, bool, 0444);
97c222a39fSBart Van Assche MODULE_PARM_DESC(never_register, "Never register memory");
98c222a39fSBart Van Assche
999c27847dSLuis R. Rodriguez static const struct kernel_param_ops srp_tmo_ops;
100ed9b2264SBart Van Assche
101a95cadb9SBart Van Assche static int srp_reconnect_delay = 10;
102a95cadb9SBart Van Assche module_param_cb(reconnect_delay, &srp_tmo_ops, &srp_reconnect_delay,
103a95cadb9SBart Van Assche S_IRUGO | S_IWUSR);
104a95cadb9SBart Van Assche MODULE_PARM_DESC(reconnect_delay, "Time between successive reconnect attempts");
105a95cadb9SBart Van Assche
106ed9b2264SBart Van Assche static int srp_fast_io_fail_tmo = 15;
107ed9b2264SBart Van Assche module_param_cb(fast_io_fail_tmo, &srp_tmo_ops, &srp_fast_io_fail_tmo,
108ed9b2264SBart Van Assche S_IRUGO | S_IWUSR);
109ed9b2264SBart Van Assche MODULE_PARM_DESC(fast_io_fail_tmo,
110ed9b2264SBart Van Assche "Number of seconds between the observation of a transport"
111ed9b2264SBart Van Assche " layer error and failing all I/O. \"off\" means that this"
112ed9b2264SBart Van Assche " functionality is disabled.");
113ed9b2264SBart Van Assche
114a95cadb9SBart Van Assche static int srp_dev_loss_tmo = 600;
115ed9b2264SBart Van Assche module_param_cb(dev_loss_tmo, &srp_tmo_ops, &srp_dev_loss_tmo,
116ed9b2264SBart Van Assche S_IRUGO | S_IWUSR);
117ed9b2264SBart Van Assche MODULE_PARM_DESC(dev_loss_tmo,
118ed9b2264SBart Van Assche "Maximum number of seconds that the SRP transport should"
119ed9b2264SBart Van Assche " insulate transport layer errors. After this time has been"
120ed9b2264SBart Van Assche " exceeded the SCSI host is removed. Should be"
121ed9b2264SBart Van Assche " between 1 and " __stringify(SCSI_DEVICE_BLOCK_MAX_TIMEOUT)
122ed9b2264SBart Van Assche " if fast_io_fail_tmo has not been set. \"off\" means that"
123ed9b2264SBart Van Assche " this functionality is disabled.");
124ed9b2264SBart Van Assche
125882981f4SBart Van Assche static bool srp_use_imm_data = true;
126882981f4SBart Van Assche module_param_named(use_imm_data, srp_use_imm_data, bool, 0644);
127882981f4SBart Van Assche MODULE_PARM_DESC(use_imm_data,
128882981f4SBart Van Assche "Whether or not to request permission to use immediate data during SRP login.");
129882981f4SBart Van Assche
130882981f4SBart Van Assche static unsigned int srp_max_imm_data = 8 * 1024;
131882981f4SBart Van Assche module_param_named(max_imm_data, srp_max_imm_data, uint, 0644);
132882981f4SBart Van Assche MODULE_PARM_DESC(max_imm_data, "Maximum immediate data size.");
133882981f4SBart Van Assche
134d92c0da7SBart Van Assche static unsigned ch_count;
135d92c0da7SBart Van Assche module_param(ch_count, uint, 0444);
136d92c0da7SBart Van Assche MODULE_PARM_DESC(ch_count,
137d92c0da7SBart Van Assche "Number of RDMA channels to use for communication with an SRP target. Using more than one channel improves performance if the HCA supports multiple completion vectors. The default value is the minimum of four times the number of online CPU sockets and the number of completion vectors supported by the HCA.");
138d92c0da7SBart Van Assche
13911a0ae4cSJason Gunthorpe static int srp_add_one(struct ib_device *device);
1407c1eb45aSHaggai Eran static void srp_remove_one(struct ib_device *device, void *client_data);
141dc1435c0SLeon Romanovsky static void srp_rename_dev(struct ib_device *device, void *client_data);
1421dc7b1f1SChristoph Hellwig static void srp_recv_done(struct ib_cq *cq, struct ib_wc *wc);
1431dc7b1f1SChristoph Hellwig static void srp_handle_qp_err(struct ib_cq *cq, struct ib_wc *wc,
1441dc7b1f1SChristoph Hellwig const char *opname);
145e7ff98aeSParav Pandit static int srp_ib_cm_handler(struct ib_cm_id *cm_id,
146e7ff98aeSParav Pandit const struct ib_cm_event *event);
14719f31343SBart Van Assche static int srp_rdma_cm_handler(struct rdma_cm_id *cm_id,
14819f31343SBart Van Assche struct rdma_cm_event *event);
149aef9ec39SRoland Dreier
1503236822bSFUJITA Tomonori static struct scsi_transport_template *ib_srp_transport_template;
151bcc05910SBart Van Assche static struct workqueue_struct *srp_remove_wq;
1523236822bSFUJITA Tomonori
153aef9ec39SRoland Dreier static struct ib_client srp_client = {
154aef9ec39SRoland Dreier .name = "srp",
155aef9ec39SRoland Dreier .add = srp_add_one,
156dc1435c0SLeon Romanovsky .remove = srp_remove_one,
157dc1435c0SLeon Romanovsky .rename = srp_rename_dev
158aef9ec39SRoland Dreier };
159aef9ec39SRoland Dreier
160c1a0b23bSMichael S. Tsirkin static struct ib_sa_client srp_sa_client;
161c1a0b23bSMichael S. Tsirkin
srp_tmo_get(char * buffer,const struct kernel_param * kp)162ed9b2264SBart Van Assche static int srp_tmo_get(char *buffer, const struct kernel_param *kp)
163ed9b2264SBart Van Assche {
164ed9b2264SBart Van Assche int tmo = *(int *)kp->arg;
165ed9b2264SBart Van Assche
166ed9b2264SBart Van Assche if (tmo >= 0)
167e28bf1f0SJoe Perches return sysfs_emit(buffer, "%d\n", tmo);
168ed9b2264SBart Van Assche else
169e28bf1f0SJoe Perches return sysfs_emit(buffer, "off\n");
170ed9b2264SBart Van Assche }
171ed9b2264SBart Van Assche
srp_tmo_set(const char * val,const struct kernel_param * kp)172ed9b2264SBart Van Assche static int srp_tmo_set(const char *val, const struct kernel_param *kp)
173ed9b2264SBart Van Assche {
174ed9b2264SBart Van Assche int tmo, res;
175ed9b2264SBart Van Assche
1763fdf70acSSagi Grimberg res = srp_parse_tmo(&tmo, val);
177ed9b2264SBart Van Assche if (res)
178ed9b2264SBart Van Assche goto out;
1793fdf70acSSagi Grimberg
180a95cadb9SBart Van Assche if (kp->arg == &srp_reconnect_delay)
181a95cadb9SBart Van Assche res = srp_tmo_valid(tmo, srp_fast_io_fail_tmo,
182a95cadb9SBart Van Assche srp_dev_loss_tmo);
183a95cadb9SBart Van Assche else if (kp->arg == &srp_fast_io_fail_tmo)
184a95cadb9SBart Van Assche res = srp_tmo_valid(srp_reconnect_delay, tmo, srp_dev_loss_tmo);
185ed9b2264SBart Van Assche else
186a95cadb9SBart Van Assche res = srp_tmo_valid(srp_reconnect_delay, srp_fast_io_fail_tmo,
187a95cadb9SBart Van Assche tmo);
188ed9b2264SBart Van Assche if (res)
189ed9b2264SBart Van Assche goto out;
190ed9b2264SBart Van Assche *(int *)kp->arg = tmo;
191ed9b2264SBart Van Assche
192ed9b2264SBart Van Assche out:
193ed9b2264SBart Van Assche return res;
194ed9b2264SBart Van Assche }
195ed9b2264SBart Van Assche
1969c27847dSLuis R. Rodriguez static const struct kernel_param_ops srp_tmo_ops = {
197ed9b2264SBart Van Assche .get = srp_tmo_get,
198ed9b2264SBart Van Assche .set = srp_tmo_set,
199ed9b2264SBart Van Assche };
200ed9b2264SBart Van Assche
host_to_target(struct Scsi_Host * host)201aef9ec39SRoland Dreier static inline struct srp_target_port *host_to_target(struct Scsi_Host *host)
202aef9ec39SRoland Dreier {
203aef9ec39SRoland Dreier return (struct srp_target_port *) host->hostdata;
204aef9ec39SRoland Dreier }
205aef9ec39SRoland Dreier
srp_target_info(struct Scsi_Host * host)206aef9ec39SRoland Dreier static const char *srp_target_info(struct Scsi_Host *host)
207aef9ec39SRoland Dreier {
208aef9ec39SRoland Dreier return host_to_target(host)->target_name;
209aef9ec39SRoland Dreier }
210aef9ec39SRoland Dreier
srp_target_is_topspin(struct srp_target_port * target)2115d7cbfd6SRoland Dreier static int srp_target_is_topspin(struct srp_target_port *target)
2125d7cbfd6SRoland Dreier {
2135d7cbfd6SRoland Dreier static const u8 topspin_oui[3] = { 0x00, 0x05, 0xad };
2143d1ff48dSRaghava Kondapalli static const u8 cisco_oui[3] = { 0x00, 0x1b, 0x0d };
2155d7cbfd6SRoland Dreier
2165d7cbfd6SRoland Dreier return topspin_workarounds &&
2173d1ff48dSRaghava Kondapalli (!memcmp(&target->ioc_guid, topspin_oui, sizeof topspin_oui) ||
2183d1ff48dSRaghava Kondapalli !memcmp(&target->ioc_guid, cisco_oui, sizeof cisco_oui));
2195d7cbfd6SRoland Dreier }
2205d7cbfd6SRoland Dreier
srp_alloc_iu(struct srp_host * host,size_t size,gfp_t gfp_mask,enum dma_data_direction direction)221aef9ec39SRoland Dreier static struct srp_iu *srp_alloc_iu(struct srp_host *host, size_t size,
222aef9ec39SRoland Dreier gfp_t gfp_mask,
223aef9ec39SRoland Dreier enum dma_data_direction direction)
224aef9ec39SRoland Dreier {
225aef9ec39SRoland Dreier struct srp_iu *iu;
226aef9ec39SRoland Dreier
227aef9ec39SRoland Dreier iu = kmalloc(sizeof *iu, gfp_mask);
228aef9ec39SRoland Dreier if (!iu)
229aef9ec39SRoland Dreier goto out;
230aef9ec39SRoland Dreier
231aef9ec39SRoland Dreier iu->buf = kzalloc(size, gfp_mask);
232aef9ec39SRoland Dreier if (!iu->buf)
233aef9ec39SRoland Dreier goto out_free_iu;
234aef9ec39SRoland Dreier
23505321937SGreg Kroah-Hartman iu->dma = ib_dma_map_single(host->srp_dev->dev, iu->buf, size,
23605321937SGreg Kroah-Hartman direction);
23705321937SGreg Kroah-Hartman if (ib_dma_mapping_error(host->srp_dev->dev, iu->dma))
238aef9ec39SRoland Dreier goto out_free_buf;
239aef9ec39SRoland Dreier
240aef9ec39SRoland Dreier iu->size = size;
241aef9ec39SRoland Dreier iu->direction = direction;
242aef9ec39SRoland Dreier
243aef9ec39SRoland Dreier return iu;
244aef9ec39SRoland Dreier
245aef9ec39SRoland Dreier out_free_buf:
246aef9ec39SRoland Dreier kfree(iu->buf);
247aef9ec39SRoland Dreier out_free_iu:
248aef9ec39SRoland Dreier kfree(iu);
249aef9ec39SRoland Dreier out:
250aef9ec39SRoland Dreier return NULL;
251aef9ec39SRoland Dreier }
252aef9ec39SRoland Dreier
srp_free_iu(struct srp_host * host,struct srp_iu * iu)253aef9ec39SRoland Dreier static void srp_free_iu(struct srp_host *host, struct srp_iu *iu)
254aef9ec39SRoland Dreier {
255aef9ec39SRoland Dreier if (!iu)
256aef9ec39SRoland Dreier return;
257aef9ec39SRoland Dreier
25805321937SGreg Kroah-Hartman ib_dma_unmap_single(host->srp_dev->dev, iu->dma, iu->size,
25905321937SGreg Kroah-Hartman iu->direction);
260aef9ec39SRoland Dreier kfree(iu->buf);
261aef9ec39SRoland Dreier kfree(iu);
262aef9ec39SRoland Dreier }
263aef9ec39SRoland Dreier
srp_qp_event(struct ib_event * event,void * context)264aef9ec39SRoland Dreier static void srp_qp_event(struct ib_event *event, void *context)
265aef9ec39SRoland Dreier {
26657363d98SSagi Grimberg pr_debug("QP event %s (%d)\n",
26757363d98SSagi Grimberg ib_event_msg(event->event), event->event);
268aef9ec39SRoland Dreier }
269aef9ec39SRoland Dreier
srp_init_ib_qp(struct srp_target_port * target,struct ib_qp * qp)27019f31343SBart Van Assche static int srp_init_ib_qp(struct srp_target_port *target,
271aef9ec39SRoland Dreier struct ib_qp *qp)
272aef9ec39SRoland Dreier {
273aef9ec39SRoland Dreier struct ib_qp_attr *attr;
274aef9ec39SRoland Dreier int ret;
275aef9ec39SRoland Dreier
276aef9ec39SRoland Dreier attr = kmalloc(sizeof *attr, GFP_KERNEL);
277aef9ec39SRoland Dreier if (!attr)
278aef9ec39SRoland Dreier return -ENOMEM;
279aef9ec39SRoland Dreier
28056b5390cSBart Van Assche ret = ib_find_cached_pkey(target->srp_host->srp_dev->dev,
281aef9ec39SRoland Dreier target->srp_host->port,
28219f31343SBart Van Assche be16_to_cpu(target->ib_cm.pkey),
283aef9ec39SRoland Dreier &attr->pkey_index);
284aef9ec39SRoland Dreier if (ret)
285aef9ec39SRoland Dreier goto out;
286aef9ec39SRoland Dreier
287aef9ec39SRoland Dreier attr->qp_state = IB_QPS_INIT;
288aef9ec39SRoland Dreier attr->qp_access_flags = (IB_ACCESS_REMOTE_READ |
289aef9ec39SRoland Dreier IB_ACCESS_REMOTE_WRITE);
290aef9ec39SRoland Dreier attr->port_num = target->srp_host->port;
291aef9ec39SRoland Dreier
292aef9ec39SRoland Dreier ret = ib_modify_qp(qp, attr,
293aef9ec39SRoland Dreier IB_QP_STATE |
294aef9ec39SRoland Dreier IB_QP_PKEY_INDEX |
295aef9ec39SRoland Dreier IB_QP_ACCESS_FLAGS |
296aef9ec39SRoland Dreier IB_QP_PORT);
297aef9ec39SRoland Dreier
298aef9ec39SRoland Dreier out:
299aef9ec39SRoland Dreier kfree(attr);
300aef9ec39SRoland Dreier return ret;
301aef9ec39SRoland Dreier }
302aef9ec39SRoland Dreier
srp_new_ib_cm_id(struct srp_rdma_ch * ch)30319f31343SBart Van Assche static int srp_new_ib_cm_id(struct srp_rdma_ch *ch)
3049fe4bcf4SDavid Dillow {
305509c07bcSBart Van Assche struct srp_target_port *target = ch->target;
3069fe4bcf4SDavid Dillow struct ib_cm_id *new_cm_id;
3079fe4bcf4SDavid Dillow
30805321937SGreg Kroah-Hartman new_cm_id = ib_create_cm_id(target->srp_host->srp_dev->dev,
30919f31343SBart Van Assche srp_ib_cm_handler, ch);
3109fe4bcf4SDavid Dillow if (IS_ERR(new_cm_id))
3119fe4bcf4SDavid Dillow return PTR_ERR(new_cm_id);
3129fe4bcf4SDavid Dillow
31319f31343SBart Van Assche if (ch->ib_cm.cm_id)
31419f31343SBart Van Assche ib_destroy_cm_id(ch->ib_cm.cm_id);
31519f31343SBart Van Assche ch->ib_cm.cm_id = new_cm_id;
3164c33bd19SDasaratharaman Chandramouli if (rdma_cap_opa_ah(target->srp_host->srp_dev->dev,
3174c33bd19SDasaratharaman Chandramouli target->srp_host->port))
31819f31343SBart Van Assche ch->ib_cm.path.rec_type = SA_PATH_REC_TYPE_OPA;
3194c33bd19SDasaratharaman Chandramouli else
32019f31343SBart Van Assche ch->ib_cm.path.rec_type = SA_PATH_REC_TYPE_IB;
32119f31343SBart Van Assche ch->ib_cm.path.sgid = target->sgid;
32219f31343SBart Van Assche ch->ib_cm.path.dgid = target->ib_cm.orig_dgid;
32319f31343SBart Van Assche ch->ib_cm.path.pkey = target->ib_cm.pkey;
32419f31343SBart Van Assche ch->ib_cm.path.service_id = target->ib_cm.service_id;
3259fe4bcf4SDavid Dillow
3269fe4bcf4SDavid Dillow return 0;
3279fe4bcf4SDavid Dillow }
3289fe4bcf4SDavid Dillow
srp_new_rdma_cm_id(struct srp_rdma_ch * ch)32919f31343SBart Van Assche static int srp_new_rdma_cm_id(struct srp_rdma_ch *ch)
33019f31343SBart Van Assche {
33119f31343SBart Van Assche struct srp_target_port *target = ch->target;
33219f31343SBart Van Assche struct rdma_cm_id *new_cm_id;
33319f31343SBart Van Assche int ret;
33419f31343SBart Van Assche
33519f31343SBart Van Assche new_cm_id = rdma_create_id(target->net, srp_rdma_cm_handler, ch,
33619f31343SBart Van Assche RDMA_PS_TCP, IB_QPT_RC);
33719f31343SBart Van Assche if (IS_ERR(new_cm_id)) {
33819f31343SBart Van Assche ret = PTR_ERR(new_cm_id);
33919f31343SBart Van Assche new_cm_id = NULL;
34019f31343SBart Van Assche goto out;
34119f31343SBart Van Assche }
34219f31343SBart Van Assche
34319f31343SBart Van Assche init_completion(&ch->done);
34419f31343SBart Van Assche ret = rdma_resolve_addr(new_cm_id, target->rdma_cm.src_specified ?
34514673778SBart Van Assche &target->rdma_cm.src.sa : NULL,
34614673778SBart Van Assche &target->rdma_cm.dst.sa,
34719f31343SBart Van Assche SRP_PATH_REC_TIMEOUT_MS);
34819f31343SBart Van Assche if (ret) {
349fdbcf5c0SBart Van Assche pr_err("No route available from %pISpsc to %pISpsc (%d)\n",
3507da09af9SBart Van Assche &target->rdma_cm.src, &target->rdma_cm.dst, ret);
35119f31343SBart Van Assche goto out;
35219f31343SBart Van Assche }
35319f31343SBart Van Assche ret = wait_for_completion_interruptible(&ch->done);
35419f31343SBart Van Assche if (ret < 0)
35519f31343SBart Van Assche goto out;
35619f31343SBart Van Assche
35719f31343SBart Van Assche ret = ch->status;
35819f31343SBart Van Assche if (ret) {
359fdbcf5c0SBart Van Assche pr_err("Resolving address %pISpsc failed (%d)\n",
3607da09af9SBart Van Assche &target->rdma_cm.dst, ret);
36119f31343SBart Van Assche goto out;
36219f31343SBart Van Assche }
36319f31343SBart Van Assche
36419f31343SBart Van Assche swap(ch->rdma_cm.cm_id, new_cm_id);
36519f31343SBart Van Assche
36619f31343SBart Van Assche out:
36719f31343SBart Van Assche if (new_cm_id)
36819f31343SBart Van Assche rdma_destroy_id(new_cm_id);
36919f31343SBart Van Assche
37019f31343SBart Van Assche return ret;
37119f31343SBart Van Assche }
37219f31343SBart Van Assche
srp_new_cm_id(struct srp_rdma_ch * ch)37319f31343SBart Van Assche static int srp_new_cm_id(struct srp_rdma_ch *ch)
37419f31343SBart Van Assche {
37519f31343SBart Van Assche struct srp_target_port *target = ch->target;
37619f31343SBart Van Assche
37719f31343SBart Van Assche return target->using_rdma_cm ? srp_new_rdma_cm_id(ch) :
37819f31343SBart Van Assche srp_new_ib_cm_id(ch);
37919f31343SBart Van Assche }
38019f31343SBart Van Assche
3815cfb1782SBart Van Assche /**
3825cfb1782SBart Van Assche * srp_destroy_fr_pool() - free the resources owned by a pool
3835cfb1782SBart Van Assche * @pool: Fast registration pool to be destroyed.
3845cfb1782SBart Van Assche */
srp_destroy_fr_pool(struct srp_fr_pool * pool)3855cfb1782SBart Van Assche static void srp_destroy_fr_pool(struct srp_fr_pool *pool)
3865cfb1782SBart Van Assche {
3875cfb1782SBart Van Assche int i;
3885cfb1782SBart Van Assche struct srp_fr_desc *d;
3895cfb1782SBart Van Assche
3905cfb1782SBart Van Assche if (!pool)
3915cfb1782SBart Van Assche return;
3925cfb1782SBart Van Assche
3935cfb1782SBart Van Assche for (i = 0, d = &pool->desc[0]; i < pool->size; i++, d++) {
3945cfb1782SBart Van Assche if (d->mr)
3955cfb1782SBart Van Assche ib_dereg_mr(d->mr);
3965cfb1782SBart Van Assche }
3975cfb1782SBart Van Assche kfree(pool);
3985cfb1782SBart Van Assche }
3995cfb1782SBart Van Assche
4005cfb1782SBart Van Assche /**
4015cfb1782SBart Van Assche * srp_create_fr_pool() - allocate and initialize a pool for fast registration
4025cfb1782SBart Van Assche * @device: IB device to allocate fast registration descriptors for.
4035cfb1782SBart Van Assche * @pd: Protection domain associated with the FR descriptors.
4045cfb1782SBart Van Assche * @pool_size: Number of descriptors to allocate.
4055cfb1782SBart Van Assche * @max_page_list_len: Maximum fast registration work request page list length.
4065cfb1782SBart Van Assche */
srp_create_fr_pool(struct ib_device * device,struct ib_pd * pd,int pool_size,int max_page_list_len)4075cfb1782SBart Van Assche static struct srp_fr_pool *srp_create_fr_pool(struct ib_device *device,
4085cfb1782SBart Van Assche struct ib_pd *pd, int pool_size,
4095cfb1782SBart Van Assche int max_page_list_len)
4105cfb1782SBart Van Assche {
4115cfb1782SBart Van Assche struct srp_fr_pool *pool;
4125cfb1782SBart Van Assche struct srp_fr_desc *d;
4135cfb1782SBart Van Assche struct ib_mr *mr;
4145cfb1782SBart Van Assche int i, ret = -EINVAL;
415fbd36818SSergey Gorenko enum ib_mr_type mr_type;
4165cfb1782SBart Van Assche
4175cfb1782SBart Van Assche if (pool_size <= 0)
4185cfb1782SBart Van Assche goto err;
4195cfb1782SBart Van Assche ret = -ENOMEM;
4207a7b0feaSGustavo A. R. Silva pool = kzalloc(struct_size(pool, desc, pool_size), GFP_KERNEL);
4215cfb1782SBart Van Assche if (!pool)
4225cfb1782SBart Van Assche goto err;
4235cfb1782SBart Van Assche pool->size = pool_size;
4245cfb1782SBart Van Assche pool->max_page_list_len = max_page_list_len;
4255cfb1782SBart Van Assche spin_lock_init(&pool->lock);
4265cfb1782SBart Van Assche INIT_LIST_HEAD(&pool->free_list);
4275cfb1782SBart Van Assche
428e945c653SJason Gunthorpe if (device->attrs.kernel_cap_flags & IBK_SG_GAPS_REG)
429fbd36818SSergey Gorenko mr_type = IB_MR_TYPE_SG_GAPS;
430fbd36818SSergey Gorenko else
431fbd36818SSergey Gorenko mr_type = IB_MR_TYPE_MEM_REG;
432fbd36818SSergey Gorenko
4335cfb1782SBart Van Assche for (i = 0, d = &pool->desc[0]; i < pool->size; i++, d++) {
434fbd36818SSergey Gorenko mr = ib_alloc_mr(pd, mr_type, max_page_list_len);
4355cfb1782SBart Van Assche if (IS_ERR(mr)) {
4365cfb1782SBart Van Assche ret = PTR_ERR(mr);
4373787d990SBart Van Assche if (ret == -ENOMEM)
4383787d990SBart Van Assche pr_info("%s: ib_alloc_mr() failed. Try to reduce max_cmd_per_lun, max_sect or ch_count\n",
4393787d990SBart Van Assche dev_name(&device->dev));
4405cfb1782SBart Van Assche goto destroy_pool;
4415cfb1782SBart Van Assche }
4425cfb1782SBart Van Assche d->mr = mr;
4435cfb1782SBart Van Assche list_add_tail(&d->entry, &pool->free_list);
4445cfb1782SBart Van Assche }
4455cfb1782SBart Van Assche
4465cfb1782SBart Van Assche out:
4475cfb1782SBart Van Assche return pool;
4485cfb1782SBart Van Assche
4495cfb1782SBart Van Assche destroy_pool:
4505cfb1782SBart Van Assche srp_destroy_fr_pool(pool);
4515cfb1782SBart Van Assche
4525cfb1782SBart Van Assche err:
4535cfb1782SBart Van Assche pool = ERR_PTR(ret);
4545cfb1782SBart Van Assche goto out;
4555cfb1782SBart Van Assche }
4565cfb1782SBart Van Assche
4575cfb1782SBart Van Assche /**
4585cfb1782SBart Van Assche * srp_fr_pool_get() - obtain a descriptor suitable for fast registration
4595cfb1782SBart Van Assche * @pool: Pool to obtain descriptor from.
4605cfb1782SBart Van Assche */
srp_fr_pool_get(struct srp_fr_pool * pool)4615cfb1782SBart Van Assche static struct srp_fr_desc *srp_fr_pool_get(struct srp_fr_pool *pool)
4625cfb1782SBart Van Assche {
4635cfb1782SBart Van Assche struct srp_fr_desc *d = NULL;
4645cfb1782SBart Van Assche unsigned long flags;
4655cfb1782SBart Van Assche
4665cfb1782SBart Van Assche spin_lock_irqsave(&pool->lock, flags);
4675cfb1782SBart Van Assche if (!list_empty(&pool->free_list)) {
4685cfb1782SBart Van Assche d = list_first_entry(&pool->free_list, typeof(*d), entry);
4695cfb1782SBart Van Assche list_del(&d->entry);
4705cfb1782SBart Van Assche }
4715cfb1782SBart Van Assche spin_unlock_irqrestore(&pool->lock, flags);
4725cfb1782SBart Van Assche
4735cfb1782SBart Van Assche return d;
4745cfb1782SBart Van Assche }
4755cfb1782SBart Van Assche
4765cfb1782SBart Van Assche /**
4775cfb1782SBart Van Assche * srp_fr_pool_put() - put an FR descriptor back in the free list
4785cfb1782SBart Van Assche * @pool: Pool the descriptor was allocated from.
4795cfb1782SBart Van Assche * @desc: Pointer to an array of fast registration descriptor pointers.
4805cfb1782SBart Van Assche * @n: Number of descriptors to put back.
4815cfb1782SBart Van Assche *
4825cfb1782SBart Van Assche * Note: The caller must already have queued an invalidation request for
4835cfb1782SBart Van Assche * desc->mr->rkey before calling this function.
4845cfb1782SBart Van Assche */
srp_fr_pool_put(struct srp_fr_pool * pool,struct srp_fr_desc ** desc,int n)4855cfb1782SBart Van Assche static void srp_fr_pool_put(struct srp_fr_pool *pool, struct srp_fr_desc **desc,
4865cfb1782SBart Van Assche int n)
4875cfb1782SBart Van Assche {
4885cfb1782SBart Van Assche unsigned long flags;
4895cfb1782SBart Van Assche int i;
4905cfb1782SBart Van Assche
4915cfb1782SBart Van Assche spin_lock_irqsave(&pool->lock, flags);
4925cfb1782SBart Van Assche for (i = 0; i < n; i++)
4935cfb1782SBart Van Assche list_add(&desc[i]->entry, &pool->free_list);
4945cfb1782SBart Van Assche spin_unlock_irqrestore(&pool->lock, flags);
4955cfb1782SBart Van Assche }
4965cfb1782SBart Van Assche
srp_alloc_fr_pool(struct srp_target_port * target)4975cfb1782SBart Van Assche static struct srp_fr_pool *srp_alloc_fr_pool(struct srp_target_port *target)
4985cfb1782SBart Van Assche {
4995cfb1782SBart Van Assche struct srp_device *dev = target->srp_host->srp_dev;
5005cfb1782SBart Van Assche
501fa9863f8SBart Van Assche return srp_create_fr_pool(dev->dev, dev->pd, target->mr_pool_size,
5025cfb1782SBart Van Assche dev->max_pages_per_mr);
5035cfb1782SBart Van Assche }
5045cfb1782SBart Van Assche
5057dad6b2eSBart Van Assche /**
5067dad6b2eSBart Van Assche * srp_destroy_qp() - destroy an RDMA queue pair
5079566b054SBart Van Assche * @ch: SRP RDMA channel.
5087dad6b2eSBart Van Assche *
509561392d4SSteve Wise * Drain the qp before destroying it. This avoids that the receive
510561392d4SSteve Wise * completion handler can access the queue pair while it is
5117dad6b2eSBart Van Assche * being destroyed.
5127dad6b2eSBart Van Assche */
srp_destroy_qp(struct srp_rdma_ch * ch)5139566b054SBart Van Assche static void srp_destroy_qp(struct srp_rdma_ch *ch)
5147dad6b2eSBart Van Assche {
5159294000dSBart Van Assche spin_lock_irq(&ch->lock);
5169294000dSBart Van Assche ib_process_cq_direct(ch->send_cq, -1);
5179294000dSBart Van Assche spin_unlock_irq(&ch->lock);
5189294000dSBart Van Assche
5199566b054SBart Van Assche ib_drain_qp(ch->qp);
5209566b054SBart Van Assche ib_destroy_qp(ch->qp);
5217dad6b2eSBart Van Assche }
5227dad6b2eSBart Van Assche
srp_create_ch_ib(struct srp_rdma_ch * ch)523509c07bcSBart Van Assche static int srp_create_ch_ib(struct srp_rdma_ch *ch)
524aef9ec39SRoland Dreier {
525509c07bcSBart Van Assche struct srp_target_port *target = ch->target;
52662154b2eSBart Van Assche struct srp_device *dev = target->srp_host->srp_dev;
527bf583470SBart Van Assche const struct ib_device_attr *attr = &dev->dev->attrs;
528aef9ec39SRoland Dreier struct ib_qp_init_attr *init_attr;
52973aa89edSIshai Rabinovitz struct ib_cq *recv_cq, *send_cq;
53073aa89edSIshai Rabinovitz struct ib_qp *qp;
5315cfb1782SBart Van Assche struct srp_fr_pool *fr_pool = NULL;
532509c5f33SBart Van Assche const int m = 1 + dev->use_fast_reg * target->mr_per_cmd * 2;
533aef9ec39SRoland Dreier int ret;
534aef9ec39SRoland Dreier
535aef9ec39SRoland Dreier init_attr = kzalloc(sizeof *init_attr, GFP_KERNEL);
536aef9ec39SRoland Dreier if (!init_attr)
537aef9ec39SRoland Dreier return -ENOMEM;
538aef9ec39SRoland Dreier
539561392d4SSteve Wise /* queue_size + 1 for ib_drain_rq() */
5401dc7b1f1SChristoph Hellwig recv_cq = ib_alloc_cq(dev->dev, ch, target->queue_size + 1,
5411dc7b1f1SChristoph Hellwig ch->comp_vector, IB_POLL_SOFTIRQ);
54273aa89edSIshai Rabinovitz if (IS_ERR(recv_cq)) {
54373aa89edSIshai Rabinovitz ret = PTR_ERR(recv_cq);
544da9d2f07SRoland Dreier goto err;
545aef9ec39SRoland Dreier }
546aef9ec39SRoland Dreier
5471dc7b1f1SChristoph Hellwig send_cq = ib_alloc_cq(dev->dev, ch, m * target->queue_size,
5481dc7b1f1SChristoph Hellwig ch->comp_vector, IB_POLL_DIRECT);
54973aa89edSIshai Rabinovitz if (IS_ERR(send_cq)) {
55073aa89edSIshai Rabinovitz ret = PTR_ERR(send_cq);
551da9d2f07SRoland Dreier goto err_recv_cq;
5529c03dc9fSBart Van Assche }
5539c03dc9fSBart Van Assche
554aef9ec39SRoland Dreier init_attr->event_handler = srp_qp_event;
5555cfb1782SBart Van Assche init_attr->cap.max_send_wr = m * target->queue_size;
5567dad6b2eSBart Van Assche init_attr->cap.max_recv_wr = target->queue_size + 1;
557aef9ec39SRoland Dreier init_attr->cap.max_recv_sge = 1;
558bf583470SBart Van Assche init_attr->cap.max_send_sge = min(SRP_MAX_SGE, attr->max_send_sge);
5595cfb1782SBart Van Assche init_attr->sq_sig_type = IB_SIGNAL_REQ_WR;
560aef9ec39SRoland Dreier init_attr->qp_type = IB_QPT_RC;
56173aa89edSIshai Rabinovitz init_attr->send_cq = send_cq;
56273aa89edSIshai Rabinovitz init_attr->recv_cq = recv_cq;
563aef9ec39SRoland Dreier
564bf583470SBart Van Assche ch->max_imm_sge = min(init_attr->cap.max_send_sge - 1U, 255U);
565bf583470SBart Van Assche
56619f31343SBart Van Assche if (target->using_rdma_cm) {
56719f31343SBart Van Assche ret = rdma_create_qp(ch->rdma_cm.cm_id, dev->pd, init_attr);
56819f31343SBart Van Assche qp = ch->rdma_cm.cm_id->qp;
56919f31343SBart Van Assche } else {
57062154b2eSBart Van Assche qp = ib_create_qp(dev->pd, init_attr);
57119f31343SBart Van Assche if (!IS_ERR(qp)) {
57219f31343SBart Van Assche ret = srp_init_ib_qp(target, qp);
57319f31343SBart Van Assche if (ret)
57419f31343SBart Van Assche ib_destroy_qp(qp);
57519f31343SBart Van Assche } else {
57673aa89edSIshai Rabinovitz ret = PTR_ERR(qp);
57719f31343SBart Van Assche }
57819f31343SBart Van Assche }
57919f31343SBart Van Assche if (ret) {
58019f31343SBart Van Assche pr_err("QP creation failed for dev %s: %d\n",
58119f31343SBart Van Assche dev_name(&dev->dev->dev), ret);
582da9d2f07SRoland Dreier goto err_send_cq;
583aef9ec39SRoland Dreier }
584aef9ec39SRoland Dreier
585002f1567SBart Van Assche if (dev->use_fast_reg) {
5865cfb1782SBart Van Assche fr_pool = srp_alloc_fr_pool(target);
5875cfb1782SBart Van Assche if (IS_ERR(fr_pool)) {
5885cfb1782SBart Van Assche ret = PTR_ERR(fr_pool);
5895cfb1782SBart Van Assche shost_printk(KERN_WARNING, target->scsi_host, PFX
5905cfb1782SBart Van Assche "FR pool allocation failed (%d)\n", ret);
5915cfb1782SBart Van Assche goto err_qp;
5925cfb1782SBart Van Assche }
593d1b4289eSBart Van Assche }
594d1b4289eSBart Van Assche
595509c07bcSBart Van Assche if (ch->qp)
5969566b054SBart Van Assche srp_destroy_qp(ch);
597509c07bcSBart Van Assche if (ch->recv_cq)
5981dc7b1f1SChristoph Hellwig ib_free_cq(ch->recv_cq);
599509c07bcSBart Van Assche if (ch->send_cq)
6001dc7b1f1SChristoph Hellwig ib_free_cq(ch->send_cq);
60173aa89edSIshai Rabinovitz
602509c07bcSBart Van Assche ch->qp = qp;
603509c07bcSBart Van Assche ch->recv_cq = recv_cq;
604509c07bcSBart Van Assche ch->send_cq = send_cq;
60573aa89edSIshai Rabinovitz
6067fbc67dfSSagi Grimberg if (dev->use_fast_reg) {
6077fbc67dfSSagi Grimberg if (ch->fr_pool)
6087fbc67dfSSagi Grimberg srp_destroy_fr_pool(ch->fr_pool);
6097fbc67dfSSagi Grimberg ch->fr_pool = fr_pool;
6107fbc67dfSSagi Grimberg }
6117fbc67dfSSagi Grimberg
612da9d2f07SRoland Dreier kfree(init_attr);
613da9d2f07SRoland Dreier return 0;
614da9d2f07SRoland Dreier
615da9d2f07SRoland Dreier err_qp:
61619f31343SBart Van Assche if (target->using_rdma_cm)
61719f31343SBart Van Assche rdma_destroy_qp(ch->rdma_cm.cm_id);
61819f31343SBart Van Assche else
61995c2ef50SIsrael Rukshin ib_destroy_qp(qp);
620da9d2f07SRoland Dreier
621da9d2f07SRoland Dreier err_send_cq:
6221dc7b1f1SChristoph Hellwig ib_free_cq(send_cq);
623da9d2f07SRoland Dreier
624da9d2f07SRoland Dreier err_recv_cq:
6251dc7b1f1SChristoph Hellwig ib_free_cq(recv_cq);
626da9d2f07SRoland Dreier
627da9d2f07SRoland Dreier err:
628aef9ec39SRoland Dreier kfree(init_attr);
629aef9ec39SRoland Dreier return ret;
630aef9ec39SRoland Dreier }
631aef9ec39SRoland Dreier
6324d73f95fSBart Van Assche /*
6334d73f95fSBart Van Assche * Note: this function may be called without srp_alloc_iu_bufs() having been
634509c07bcSBart Van Assche * invoked. Hence the ch->[rt]x_ring checks.
6354d73f95fSBart Van Assche */
srp_free_ch_ib(struct srp_target_port * target,struct srp_rdma_ch * ch)636509c07bcSBart Van Assche static void srp_free_ch_ib(struct srp_target_port *target,
637509c07bcSBart Van Assche struct srp_rdma_ch *ch)
638aef9ec39SRoland Dreier {
6395cfb1782SBart Van Assche struct srp_device *dev = target->srp_host->srp_dev;
640aef9ec39SRoland Dreier int i;
641aef9ec39SRoland Dreier
642d92c0da7SBart Van Assche if (!ch->target)
643d92c0da7SBart Van Assche return;
644d92c0da7SBart Van Assche
64519f31343SBart Van Assche if (target->using_rdma_cm) {
64619f31343SBart Van Assche if (ch->rdma_cm.cm_id) {
64719f31343SBart Van Assche rdma_destroy_id(ch->rdma_cm.cm_id);
64819f31343SBart Van Assche ch->rdma_cm.cm_id = NULL;
64919f31343SBart Van Assche }
65019f31343SBart Van Assche } else {
65119f31343SBart Van Assche if (ch->ib_cm.cm_id) {
65219f31343SBart Van Assche ib_destroy_cm_id(ch->ib_cm.cm_id);
65319f31343SBart Van Assche ch->ib_cm.cm_id = NULL;
65419f31343SBart Van Assche }
655394c595eSBart Van Assche }
656394c595eSBart Van Assche
657d92c0da7SBart Van Assche /* If srp_new_cm_id() succeeded but srp_create_ch_ib() not, return. */
658d92c0da7SBart Van Assche if (!ch->qp)
659d92c0da7SBart Van Assche return;
660d92c0da7SBart Van Assche
6615cfb1782SBart Van Assche if (dev->use_fast_reg) {
662509c07bcSBart Van Assche if (ch->fr_pool)
663509c07bcSBart Van Assche srp_destroy_fr_pool(ch->fr_pool);
6645cfb1782SBart Van Assche }
6651dc7b1f1SChristoph Hellwig
6669566b054SBart Van Assche srp_destroy_qp(ch);
6671dc7b1f1SChristoph Hellwig ib_free_cq(ch->send_cq);
6681dc7b1f1SChristoph Hellwig ib_free_cq(ch->recv_cq);
669aef9ec39SRoland Dreier
670d92c0da7SBart Van Assche /*
671d92c0da7SBart Van Assche * Avoid that the SCSI error handler tries to use this channel after
672d92c0da7SBart Van Assche * it has been freed. The SCSI error handler can namely continue
673d92c0da7SBart Van Assche * trying to perform recovery actions after scsi_remove_host()
674d92c0da7SBart Van Assche * returned.
675d92c0da7SBart Van Assche */
676d92c0da7SBart Van Assche ch->target = NULL;
677d92c0da7SBart Van Assche
678509c07bcSBart Van Assche ch->qp = NULL;
679509c07bcSBart Van Assche ch->send_cq = ch->recv_cq = NULL;
68073aa89edSIshai Rabinovitz
681509c07bcSBart Van Assche if (ch->rx_ring) {
6824d73f95fSBart Van Assche for (i = 0; i < target->queue_size; ++i)
683509c07bcSBart Van Assche srp_free_iu(target->srp_host, ch->rx_ring[i]);
684509c07bcSBart Van Assche kfree(ch->rx_ring);
685509c07bcSBart Van Assche ch->rx_ring = NULL;
6864d73f95fSBart Van Assche }
687509c07bcSBart Van Assche if (ch->tx_ring) {
6884d73f95fSBart Van Assche for (i = 0; i < target->queue_size; ++i)
689509c07bcSBart Van Assche srp_free_iu(target->srp_host, ch->tx_ring[i]);
690509c07bcSBart Van Assche kfree(ch->tx_ring);
691509c07bcSBart Van Assche ch->tx_ring = NULL;
6924d73f95fSBart Van Assche }
693aef9ec39SRoland Dreier }
694aef9ec39SRoland Dreier
srp_path_rec_completion(int status,struct sa_path_rec * pathrec,unsigned int num_paths,void * ch_ptr)695aef9ec39SRoland Dreier static void srp_path_rec_completion(int status,
696c2f8fc4eSDasaratharaman Chandramouli struct sa_path_rec *pathrec,
697ccae0447SMark Zhang unsigned int num_paths, void *ch_ptr)
698aef9ec39SRoland Dreier {
699509c07bcSBart Van Assche struct srp_rdma_ch *ch = ch_ptr;
700509c07bcSBart Van Assche struct srp_target_port *target = ch->target;
701aef9ec39SRoland Dreier
702509c07bcSBart Van Assche ch->status = status;
703aef9ec39SRoland Dreier if (status)
7047aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host,
7057aa54bd7SDavid Dillow PFX "Got failed path rec status %d\n", status);
706aef9ec39SRoland Dreier else
70719f31343SBart Van Assche ch->ib_cm.path = *pathrec;
708509c07bcSBart Van Assche complete(&ch->done);
709aef9ec39SRoland Dreier }
710aef9ec39SRoland Dreier
srp_ib_lookup_path(struct srp_rdma_ch * ch)71119f31343SBart Van Assche static int srp_ib_lookup_path(struct srp_rdma_ch *ch)
712aef9ec39SRoland Dreier {
713509c07bcSBart Van Assche struct srp_target_port *target = ch->target;
714c74ff750SBart Van Assche int ret;
715a702adceSBart Van Assche
71619f31343SBart Van Assche ch->ib_cm.path.numb_path = 1;
717aef9ec39SRoland Dreier
718509c07bcSBart Van Assche init_completion(&ch->done);
719aef9ec39SRoland Dreier
72019f31343SBart Van Assche ch->ib_cm.path_query_id = ib_sa_path_rec_get(&srp_sa_client,
72105321937SGreg Kroah-Hartman target->srp_host->srp_dev->dev,
722aef9ec39SRoland Dreier target->srp_host->port,
72319f31343SBart Van Assche &ch->ib_cm.path,
724247e020eSSean Hefty IB_SA_PATH_REC_SERVICE_ID |
725aef9ec39SRoland Dreier IB_SA_PATH_REC_DGID |
726aef9ec39SRoland Dreier IB_SA_PATH_REC_SGID |
727aef9ec39SRoland Dreier IB_SA_PATH_REC_NUMB_PATH |
728aef9ec39SRoland Dreier IB_SA_PATH_REC_PKEY,
729aef9ec39SRoland Dreier SRP_PATH_REC_TIMEOUT_MS,
730aef9ec39SRoland Dreier GFP_KERNEL,
731aef9ec39SRoland Dreier srp_path_rec_completion,
73219f31343SBart Van Assche ch, &ch->ib_cm.path_query);
733c74ff750SBart Van Assche if (ch->ib_cm.path_query_id < 0)
734c74ff750SBart Van Assche return ch->ib_cm.path_query_id;
735aef9ec39SRoland Dreier
736509c07bcSBart Van Assche ret = wait_for_completion_interruptible(&ch->done);
737a702adceSBart Van Assche if (ret < 0)
738c74ff750SBart Van Assche return ret;
739aef9ec39SRoland Dreier
740c74ff750SBart Van Assche if (ch->status < 0)
7417aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host,
74285769c6fSBart Van Assche PFX "Path record query failed: sgid %pI6, dgid %pI6, pkey %#04x, service_id %#16llx\n",
74319f31343SBart Van Assche ch->ib_cm.path.sgid.raw, ch->ib_cm.path.dgid.raw,
74419f31343SBart Van Assche be16_to_cpu(target->ib_cm.pkey),
74519f31343SBart Van Assche be64_to_cpu(target->ib_cm.service_id));
746aef9ec39SRoland Dreier
747c74ff750SBart Van Assche return ch->status;
748aef9ec39SRoland Dreier }
749aef9ec39SRoland Dreier
srp_rdma_lookup_path(struct srp_rdma_ch * ch)75019f31343SBart Van Assche static int srp_rdma_lookup_path(struct srp_rdma_ch *ch)
75119f31343SBart Van Assche {
75219f31343SBart Van Assche struct srp_target_port *target = ch->target;
75319f31343SBart Van Assche int ret;
75419f31343SBart Van Assche
75519f31343SBart Van Assche init_completion(&ch->done);
75619f31343SBart Van Assche
75719f31343SBart Van Assche ret = rdma_resolve_route(ch->rdma_cm.cm_id, SRP_PATH_REC_TIMEOUT_MS);
75819f31343SBart Van Assche if (ret)
75919f31343SBart Van Assche return ret;
76019f31343SBart Van Assche
76119f31343SBart Van Assche wait_for_completion_interruptible(&ch->done);
76219f31343SBart Van Assche
76319f31343SBart Van Assche if (ch->status != 0)
76419f31343SBart Van Assche shost_printk(KERN_WARNING, target->scsi_host,
76519f31343SBart Van Assche PFX "Path resolution failed\n");
76619f31343SBart Van Assche
76719f31343SBart Van Assche return ch->status;
76819f31343SBart Van Assche }
76919f31343SBart Van Assche
srp_lookup_path(struct srp_rdma_ch * ch)77019f31343SBart Van Assche static int srp_lookup_path(struct srp_rdma_ch *ch)
77119f31343SBart Van Assche {
77219f31343SBart Van Assche struct srp_target_port *target = ch->target;
77319f31343SBart Van Assche
77419f31343SBart Van Assche return target->using_rdma_cm ? srp_rdma_lookup_path(ch) :
77519f31343SBart Van Assche srp_ib_lookup_path(ch);
77619f31343SBart Van Assche }
77719f31343SBart Van Assche
srp_get_subnet_timeout(struct srp_host * host)7784c532d6cSBart Van Assche static u8 srp_get_subnet_timeout(struct srp_host *host)
7794c532d6cSBart Van Assche {
7804c532d6cSBart Van Assche struct ib_port_attr attr;
7814c532d6cSBart Van Assche int ret;
7824c532d6cSBart Van Assche u8 subnet_timeout = 18;
7834c532d6cSBart Van Assche
7844c532d6cSBart Van Assche ret = ib_query_port(host->srp_dev->dev, host->port, &attr);
7854c532d6cSBart Van Assche if (ret == 0)
7864c532d6cSBart Van Assche subnet_timeout = attr.subnet_timeout;
7874c532d6cSBart Van Assche
7884c532d6cSBart Van Assche if (unlikely(subnet_timeout < 15))
7894c532d6cSBart Van Assche pr_warn("%s: subnet timeout %d may cause SRP login to fail.\n",
7904c532d6cSBart Van Assche dev_name(&host->srp_dev->dev->dev), subnet_timeout);
7914c532d6cSBart Van Assche
7924c532d6cSBart Van Assche return subnet_timeout;
7934c532d6cSBart Van Assche }
7944c532d6cSBart Van Assche
srp_send_req(struct srp_rdma_ch * ch,uint32_t max_iu_len,bool multich)795513d5647SBart Van Assche static int srp_send_req(struct srp_rdma_ch *ch, uint32_t max_iu_len,
796513d5647SBart Van Assche bool multich)
797aef9ec39SRoland Dreier {
798509c07bcSBart Van Assche struct srp_target_port *target = ch->target;
799aef9ec39SRoland Dreier struct {
80019f31343SBart Van Assche struct rdma_conn_param rdma_param;
80119f31343SBart Van Assche struct srp_login_req_rdma rdma_req;
80219f31343SBart Van Assche struct ib_cm_req_param ib_param;
80319f31343SBart Van Assche struct srp_login_req ib_req;
804aef9ec39SRoland Dreier } *req = NULL;
80548900a28SBart Van Assche char *ipi, *tpi;
806aef9ec39SRoland Dreier int status;
807aef9ec39SRoland Dreier
808aef9ec39SRoland Dreier req = kzalloc(sizeof *req, GFP_KERNEL);
809aef9ec39SRoland Dreier if (!req)
810aef9ec39SRoland Dreier return -ENOMEM;
811aef9ec39SRoland Dreier
81219f31343SBart Van Assche req->ib_param.flow_control = 1;
81319f31343SBart Van Assche req->ib_param.retry_count = target->tl_retry_count;
814aef9ec39SRoland Dreier
815aef9ec39SRoland Dreier /*
816aef9ec39SRoland Dreier * Pick some arbitrary defaults here; we could make these
817aef9ec39SRoland Dreier * module parameters if anyone cared about setting them.
818aef9ec39SRoland Dreier */
81919f31343SBart Van Assche req->ib_param.responder_resources = 4;
82019f31343SBart Van Assche req->ib_param.rnr_retry_count = 7;
82119f31343SBart Van Assche req->ib_param.max_cm_retries = 15;
822aef9ec39SRoland Dreier
82319f31343SBart Van Assche req->ib_req.opcode = SRP_LOGIN_REQ;
82419f31343SBart Van Assche req->ib_req.tag = 0;
825513d5647SBart Van Assche req->ib_req.req_it_iu_len = cpu_to_be32(max_iu_len);
82619f31343SBart Van Assche req->ib_req.req_buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT |
827aef9ec39SRoland Dreier SRP_BUF_FORMAT_INDIRECT);
82819f31343SBart Van Assche req->ib_req.req_flags = (multich ? SRP_MULTICHAN_MULTI :
829d92c0da7SBart Van Assche SRP_MULTICHAN_SINGLE);
830882981f4SBart Van Assche if (srp_use_imm_data) {
831882981f4SBart Van Assche req->ib_req.req_flags |= SRP_IMMED_REQUESTED;
832882981f4SBart Van Assche req->ib_req.imm_data_offset = cpu_to_be16(SRP_IMM_DATA_OFFSET);
833882981f4SBart Van Assche }
83448900a28SBart Van Assche
83519f31343SBart Van Assche if (target->using_rdma_cm) {
83619f31343SBart Van Assche req->rdma_param.flow_control = req->ib_param.flow_control;
83719f31343SBart Van Assche req->rdma_param.responder_resources =
83819f31343SBart Van Assche req->ib_param.responder_resources;
83919f31343SBart Van Assche req->rdma_param.initiator_depth = req->ib_param.initiator_depth;
84019f31343SBart Van Assche req->rdma_param.retry_count = req->ib_param.retry_count;
84119f31343SBart Van Assche req->rdma_param.rnr_retry_count = req->ib_param.rnr_retry_count;
84219f31343SBart Van Assche req->rdma_param.private_data = &req->rdma_req;
84319f31343SBart Van Assche req->rdma_param.private_data_len = sizeof(req->rdma_req);
84419f31343SBart Van Assche
84519f31343SBart Van Assche req->rdma_req.opcode = req->ib_req.opcode;
84619f31343SBart Van Assche req->rdma_req.tag = req->ib_req.tag;
84719f31343SBart Van Assche req->rdma_req.req_it_iu_len = req->ib_req.req_it_iu_len;
84819f31343SBart Van Assche req->rdma_req.req_buf_fmt = req->ib_req.req_buf_fmt;
84919f31343SBart Van Assche req->rdma_req.req_flags = req->ib_req.req_flags;
850882981f4SBart Van Assche req->rdma_req.imm_data_offset = req->ib_req.imm_data_offset;
85119f31343SBart Van Assche
85219f31343SBart Van Assche ipi = req->rdma_req.initiator_port_id;
85319f31343SBart Van Assche tpi = req->rdma_req.target_port_id;
85419f31343SBart Van Assche } else {
85548900a28SBart Van Assche u8 subnet_timeout;
85648900a28SBart Van Assche
85748900a28SBart Van Assche subnet_timeout = srp_get_subnet_timeout(target->srp_host);
85848900a28SBart Van Assche
85919f31343SBart Van Assche req->ib_param.primary_path = &ch->ib_cm.path;
86019f31343SBart Van Assche req->ib_param.alternate_path = NULL;
86119f31343SBart Van Assche req->ib_param.service_id = target->ib_cm.service_id;
86219f31343SBart Van Assche get_random_bytes(&req->ib_param.starting_psn, 4);
86319f31343SBart Van Assche req->ib_param.starting_psn &= 0xffffff;
86419f31343SBart Van Assche req->ib_param.qp_num = ch->qp->qp_num;
86519f31343SBart Van Assche req->ib_param.qp_type = ch->qp->qp_type;
86619f31343SBart Van Assche req->ib_param.local_cm_response_timeout = subnet_timeout + 2;
86719f31343SBart Van Assche req->ib_param.remote_cm_response_timeout = subnet_timeout + 2;
86819f31343SBart Van Assche req->ib_param.private_data = &req->ib_req;
86919f31343SBart Van Assche req->ib_param.private_data_len = sizeof(req->ib_req);
87048900a28SBart Van Assche
87119f31343SBart Van Assche ipi = req->ib_req.initiator_port_id;
87219f31343SBart Van Assche tpi = req->ib_req.target_port_id;
87348900a28SBart Van Assche }
87448900a28SBart Van Assche
8750c0450dbSRamachandra K /*
8760c0450dbSRamachandra K * In the published SRP specification (draft rev. 16a), the
8770c0450dbSRamachandra K * port identifier format is 8 bytes of ID extension followed
8780c0450dbSRamachandra K * by 8 bytes of GUID. Older drafts put the two halves in the
8790c0450dbSRamachandra K * opposite order, so that the GUID comes first.
8800c0450dbSRamachandra K *
8810c0450dbSRamachandra K * Targets conforming to these obsolete drafts can be
8820c0450dbSRamachandra K * recognized by the I/O Class they report.
8830c0450dbSRamachandra K */
8840c0450dbSRamachandra K if (target->io_class == SRP_REV10_IB_IO_CLASS) {
88548900a28SBart Van Assche memcpy(ipi, &target->sgid.global.interface_id, 8);
88648900a28SBart Van Assche memcpy(ipi + 8, &target->initiator_ext, 8);
88748900a28SBart Van Assche memcpy(tpi, &target->ioc_guid, 8);
88848900a28SBart Van Assche memcpy(tpi + 8, &target->id_ext, 8);
8890c0450dbSRamachandra K } else {
89048900a28SBart Van Assche memcpy(ipi, &target->initiator_ext, 8);
89148900a28SBart Van Assche memcpy(ipi + 8, &target->sgid.global.interface_id, 8);
89248900a28SBart Van Assche memcpy(tpi, &target->id_ext, 8);
89348900a28SBart Van Assche memcpy(tpi + 8, &target->ioc_guid, 8);
8940c0450dbSRamachandra K }
8950c0450dbSRamachandra K
896aef9ec39SRoland Dreier /*
897aef9ec39SRoland Dreier * Topspin/Cisco SRP targets will reject our login unless we
89801cb9bcbSIshai Rabinovitz * zero out the first 8 bytes of our initiator port ID and set
89901cb9bcbSIshai Rabinovitz * the second 8 bytes to the local node GUID.
900aef9ec39SRoland Dreier */
9015d7cbfd6SRoland Dreier if (srp_target_is_topspin(target)) {
9027aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, target->scsi_host,
9037aa54bd7SDavid Dillow PFX "Topspin/Cisco initiator port ID workaround "
904aef9ec39SRoland Dreier "activated for target GUID %016llx\n",
90545c37cadSBart Van Assche be64_to_cpu(target->ioc_guid));
90648900a28SBart Van Assche memset(ipi, 0, 8);
90748900a28SBart Van Assche memcpy(ipi + 8, &target->srp_host->srp_dev->dev->node_guid, 8);
908aef9ec39SRoland Dreier }
909aef9ec39SRoland Dreier
91019f31343SBart Van Assche if (target->using_rdma_cm)
91119f31343SBart Van Assche status = rdma_connect(ch->rdma_cm.cm_id, &req->rdma_param);
91219f31343SBart Van Assche else
91319f31343SBart Van Assche status = ib_send_cm_req(ch->ib_cm.cm_id, &req->ib_param);
914aef9ec39SRoland Dreier
915aef9ec39SRoland Dreier kfree(req);
916aef9ec39SRoland Dreier
917aef9ec39SRoland Dreier return status;
918aef9ec39SRoland Dreier }
919aef9ec39SRoland Dreier
srp_queue_remove_work(struct srp_target_port * target)920ef6c49d8SBart Van Assche static bool srp_queue_remove_work(struct srp_target_port *target)
921ef6c49d8SBart Van Assche {
922ef6c49d8SBart Van Assche bool changed = false;
923ef6c49d8SBart Van Assche
924ef6c49d8SBart Van Assche spin_lock_irq(&target->lock);
925ef6c49d8SBart Van Assche if (target->state != SRP_TARGET_REMOVED) {
926ef6c49d8SBart Van Assche target->state = SRP_TARGET_REMOVED;
927ef6c49d8SBart Van Assche changed = true;
928ef6c49d8SBart Van Assche }
929ef6c49d8SBart Van Assche spin_unlock_irq(&target->lock);
930ef6c49d8SBart Van Assche
931ef6c49d8SBart Van Assche if (changed)
932bcc05910SBart Van Assche queue_work(srp_remove_wq, &target->remove_work);
933ef6c49d8SBart Van Assche
934ef6c49d8SBart Van Assche return changed;
935ef6c49d8SBart Van Assche }
936ef6c49d8SBart Van Assche
srp_disconnect_target(struct srp_target_port * target)937aef9ec39SRoland Dreier static void srp_disconnect_target(struct srp_target_port *target)
938aef9ec39SRoland Dreier {
939d92c0da7SBart Van Assche struct srp_rdma_ch *ch;
94019f31343SBart Van Assche int i, ret;
941509c07bcSBart Van Assche
942aef9ec39SRoland Dreier /* XXX should send SRP_I_LOGOUT request */
943aef9ec39SRoland Dreier
944d92c0da7SBart Van Assche for (i = 0; i < target->ch_count; i++) {
945d92c0da7SBart Van Assche ch = &target->ch[i];
946c014c8cdSBart Van Assche ch->connected = false;
94719f31343SBart Van Assche ret = 0;
94819f31343SBart Van Assche if (target->using_rdma_cm) {
94919f31343SBart Van Assche if (ch->rdma_cm.cm_id)
95019f31343SBart Van Assche rdma_disconnect(ch->rdma_cm.cm_id);
95119f31343SBart Van Assche } else {
95219f31343SBart Van Assche if (ch->ib_cm.cm_id)
95319f31343SBart Van Assche ret = ib_send_cm_dreq(ch->ib_cm.cm_id,
95419f31343SBart Van Assche NULL, 0);
95519f31343SBart Van Assche }
95619f31343SBart Van Assche if (ret < 0) {
9577aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, target->scsi_host,
9587aa54bd7SDavid Dillow PFX "Sending CM DREQ failed\n");
959aef9ec39SRoland Dreier }
960294c875aSBart Van Assche }
961294c875aSBart Van Assche }
962aef9ec39SRoland Dreier
srp_exit_cmd_priv(struct Scsi_Host * shost,struct scsi_cmnd * cmd)963ad215aaeSBart Van Assche static int srp_exit_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
9648f26c9ffSDavid Dillow {
965ad215aaeSBart Van Assche struct srp_target_port *target = host_to_target(shost);
9665cfb1782SBart Van Assche struct srp_device *dev = target->srp_host->srp_dev;
9675cfb1782SBart Van Assche struct ib_device *ibdev = dev->dev;
968ad215aaeSBart Van Assche struct srp_request *req = scsi_cmd_priv(cmd);
9698f26c9ffSDavid Dillow
9705cfb1782SBart Van Assche kfree(req->fr_list);
971c07d424dSDavid Dillow if (req->indirect_dma_addr) {
972c07d424dSDavid Dillow ib_dma_unmap_single(ibdev, req->indirect_dma_addr,
973c07d424dSDavid Dillow target->indirect_size,
974c07d424dSDavid Dillow DMA_TO_DEVICE);
975c07d424dSDavid Dillow }
976c07d424dSDavid Dillow kfree(req->indirect_desc);
977ad215aaeSBart Van Assche
978ad215aaeSBart Van Assche return 0;
9798f26c9ffSDavid Dillow }
9804d73f95fSBart Van Assche
srp_init_cmd_priv(struct Scsi_Host * shost,struct scsi_cmnd * cmd)981ad215aaeSBart Van Assche static int srp_init_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
982b81d00bdSBart Van Assche {
983ad215aaeSBart Van Assche struct srp_target_port *target = host_to_target(shost);
984b81d00bdSBart Van Assche struct srp_device *srp_dev = target->srp_host->srp_dev;
985b81d00bdSBart Van Assche struct ib_device *ibdev = srp_dev->dev;
986ad215aaeSBart Van Assche struct srp_request *req = scsi_cmd_priv(cmd);
987b81d00bdSBart Van Assche dma_addr_t dma_addr;
988ad215aaeSBart Van Assche int ret = -ENOMEM;
989b81d00bdSBart Van Assche
9907ec2e27aSBart Van Assche if (srp_dev->use_fast_reg) {
991ad215aaeSBart Van Assche req->fr_list = kmalloc_array(target->mr_per_cmd, sizeof(void *),
992ad215aaeSBart Van Assche GFP_KERNEL);
9937ec2e27aSBart Van Assche if (!req->fr_list)
9945cfb1782SBart Van Assche goto out;
9957ec2e27aSBart Van Assche }
996b81d00bdSBart Van Assche req->indirect_desc = kmalloc(target->indirect_size, GFP_KERNEL);
9975cfb1782SBart Van Assche if (!req->indirect_desc)
998b81d00bdSBart Van Assche goto out;
999b81d00bdSBart Van Assche
1000b81d00bdSBart Van Assche dma_addr = ib_dma_map_single(ibdev, req->indirect_desc,
1001b81d00bdSBart Van Assche target->indirect_size,
1002b81d00bdSBart Van Assche DMA_TO_DEVICE);
1003ad215aaeSBart Van Assche if (ib_dma_mapping_error(ibdev, dma_addr)) {
1004ad215aaeSBart Van Assche srp_exit_cmd_priv(shost, cmd);
1005b81d00bdSBart Van Assche goto out;
1006ad215aaeSBart Van Assche }
1007b81d00bdSBart Van Assche
1008b81d00bdSBart Van Assche req->indirect_dma_addr = dma_addr;
1009b81d00bdSBart Van Assche ret = 0;
1010b81d00bdSBart Van Assche
1011b81d00bdSBart Van Assche out:
1012b81d00bdSBart Van Assche return ret;
1013b81d00bdSBart Van Assche }
1014b81d00bdSBart Van Assche
1015683b159aSBart Van Assche /**
1016683b159aSBart Van Assche * srp_del_scsi_host_attr() - Remove attributes defined in the host template.
1017683b159aSBart Van Assche * @shost: SCSI host whose attributes to remove from sysfs.
1018683b159aSBart Van Assche *
1019683b159aSBart Van Assche * Note: Any attributes defined in the host template and that did not exist
1020683b159aSBart Van Assche * before invocation of this function will be ignored.
1021683b159aSBart Van Assche */
srp_del_scsi_host_attr(struct Scsi_Host * shost)1022683b159aSBart Van Assche static void srp_del_scsi_host_attr(struct Scsi_Host *shost)
1023683b159aSBart Van Assche {
1024a3cf94c9SBart Van Assche const struct attribute_group **g;
1025a3cf94c9SBart Van Assche struct attribute **attr;
1026683b159aSBart Van Assche
1027a3cf94c9SBart Van Assche for (g = shost->hostt->shost_groups; *g; ++g) {
1028a3cf94c9SBart Van Assche for (attr = (*g)->attrs; *attr; ++attr) {
1029a3cf94c9SBart Van Assche struct device_attribute *dev_attr =
1030a3cf94c9SBart Van Assche container_of(*attr, typeof(*dev_attr), attr);
1031a3cf94c9SBart Van Assche
1032a3cf94c9SBart Van Assche device_remove_file(&shost->shost_dev, dev_attr);
1033a3cf94c9SBart Van Assche }
1034a3cf94c9SBart Van Assche }
1035683b159aSBart Van Assche }
1036683b159aSBart Van Assche
srp_remove_target(struct srp_target_port * target)1037ee12d6a8SBart Van Assche static void srp_remove_target(struct srp_target_port *target)
1038ee12d6a8SBart Van Assche {
1039d92c0da7SBart Van Assche struct srp_rdma_ch *ch;
1040d92c0da7SBart Van Assche int i;
1041509c07bcSBart Van Assche
1042ef6c49d8SBart Van Assche WARN_ON_ONCE(target->state != SRP_TARGET_REMOVED);
1043ef6c49d8SBart Van Assche
1044ee12d6a8SBart Van Assche srp_del_scsi_host_attr(target->scsi_host);
10459dd69a60SBart Van Assche srp_rport_get(target->rport);
1046ee12d6a8SBart Van Assche srp_remove_host(target->scsi_host);
1047ee12d6a8SBart Van Assche scsi_remove_host(target->scsi_host);
104893079162SBart Van Assche srp_stop_rport_timers(target->rport);
1049ef6c49d8SBart Van Assche srp_disconnect_target(target);
105019f31343SBart Van Assche kobj_ns_drop(KOBJ_NS_TYPE_NET, target->net);
1051d92c0da7SBart Van Assche for (i = 0; i < target->ch_count; i++) {
1052d92c0da7SBart Van Assche ch = &target->ch[i];
1053509c07bcSBart Van Assche srp_free_ch_ib(target, ch);
1054d92c0da7SBart Van Assche }
1055c1120f89SBart Van Assche cancel_work_sync(&target->tl_err_work);
10569dd69a60SBart Van Assche srp_rport_put(target->rport);
1057d92c0da7SBart Van Assche kfree(target->ch);
1058d92c0da7SBart Van Assche target->ch = NULL;
105965d7dd2fSVu Pham
106065d7dd2fSVu Pham spin_lock(&target->srp_host->target_lock);
106165d7dd2fSVu Pham list_del(&target->list);
106265d7dd2fSVu Pham spin_unlock(&target->srp_host->target_lock);
106365d7dd2fSVu Pham
1064ee12d6a8SBart Van Assche scsi_host_put(target->scsi_host);
1065ee12d6a8SBart Van Assche }
1066ee12d6a8SBart Van Assche
srp_remove_work(struct work_struct * work)1067c4028958SDavid Howells static void srp_remove_work(struct work_struct *work)
1068aef9ec39SRoland Dreier {
1069c4028958SDavid Howells struct srp_target_port *target =
1070ef6c49d8SBart Van Assche container_of(work, struct srp_target_port, remove_work);
1071aef9ec39SRoland Dreier
1072ef6c49d8SBart Van Assche WARN_ON_ONCE(target->state != SRP_TARGET_REMOVED);
1073aef9ec39SRoland Dreier
107496fc248aSBart Van Assche srp_remove_target(target);
1075aef9ec39SRoland Dreier }
1076aef9ec39SRoland Dreier
srp_rport_delete(struct srp_rport * rport)1077dc1bdbd9SBart Van Assche static void srp_rport_delete(struct srp_rport *rport)
1078dc1bdbd9SBart Van Assche {
1079dc1bdbd9SBart Van Assche struct srp_target_port *target = rport->lld_data;
1080dc1bdbd9SBart Van Assche
1081dc1bdbd9SBart Van Assche srp_queue_remove_work(target);
1082dc1bdbd9SBart Van Assche }
1083dc1bdbd9SBart Van Assche
1084c014c8cdSBart Van Assche /**
1085c014c8cdSBart Van Assche * srp_connected_ch() - number of connected channels
1086c014c8cdSBart Van Assche * @target: SRP target port.
1087c014c8cdSBart Van Assche */
srp_connected_ch(struct srp_target_port * target)1088c014c8cdSBart Van Assche static int srp_connected_ch(struct srp_target_port *target)
1089c014c8cdSBart Van Assche {
1090c014c8cdSBart Van Assche int i, c = 0;
1091c014c8cdSBart Van Assche
1092c014c8cdSBart Van Assche for (i = 0; i < target->ch_count; i++)
1093c014c8cdSBart Van Assche c += target->ch[i].connected;
1094c014c8cdSBart Van Assche
1095c014c8cdSBart Van Assche return c;
1096c014c8cdSBart Van Assche }
1097c014c8cdSBart Van Assche
srp_connect_ch(struct srp_rdma_ch * ch,uint32_t max_iu_len,bool multich)1098513d5647SBart Van Assche static int srp_connect_ch(struct srp_rdma_ch *ch, uint32_t max_iu_len,
1099513d5647SBart Van Assche bool multich)
1100aef9ec39SRoland Dreier {
1101509c07bcSBart Van Assche struct srp_target_port *target = ch->target;
1102aef9ec39SRoland Dreier int ret;
1103aef9ec39SRoland Dreier
1104c014c8cdSBart Van Assche WARN_ON_ONCE(!multich && srp_connected_ch(target) > 0);
1105294c875aSBart Van Assche
1106509c07bcSBart Van Assche ret = srp_lookup_path(ch);
1107aef9ec39SRoland Dreier if (ret)
11084d59ad29SBart Van Assche goto out;
1109aef9ec39SRoland Dreier
1110aef9ec39SRoland Dreier while (1) {
1111509c07bcSBart Van Assche init_completion(&ch->done);
1112513d5647SBart Van Assche ret = srp_send_req(ch, max_iu_len, multich);
1113aef9ec39SRoland Dreier if (ret)
11144d59ad29SBart Van Assche goto out;
1115509c07bcSBart Van Assche ret = wait_for_completion_interruptible(&ch->done);
1116a702adceSBart Van Assche if (ret < 0)
11174d59ad29SBart Van Assche goto out;
1118aef9ec39SRoland Dreier
1119aef9ec39SRoland Dreier /*
1120aef9ec39SRoland Dreier * The CM event handling code will set status to
1121aef9ec39SRoland Dreier * SRP_PORT_REDIRECT if we get a port redirect REJ
1122aef9ec39SRoland Dreier * back, or SRP_DLID_REDIRECT if we get a lid/qp
1123aef9ec39SRoland Dreier * redirect REJ back.
1124aef9ec39SRoland Dreier */
11254d59ad29SBart Van Assche ret = ch->status;
11264d59ad29SBart Van Assche switch (ret) {
1127aef9ec39SRoland Dreier case 0:
1128c014c8cdSBart Van Assche ch->connected = true;
11294d59ad29SBart Van Assche goto out;
1130aef9ec39SRoland Dreier
1131aef9ec39SRoland Dreier case SRP_PORT_REDIRECT:
1132509c07bcSBart Van Assche ret = srp_lookup_path(ch);
1133aef9ec39SRoland Dreier if (ret)
11344d59ad29SBart Van Assche goto out;
1135aef9ec39SRoland Dreier break;
1136aef9ec39SRoland Dreier
1137aef9ec39SRoland Dreier case SRP_DLID_REDIRECT:
1138aef9ec39SRoland Dreier break;
1139aef9ec39SRoland Dreier
11409fe4bcf4SDavid Dillow case SRP_STALE_CONN:
11419fe4bcf4SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX
11429fe4bcf4SDavid Dillow "giving up on stale connection\n");
11434d59ad29SBart Van Assche ret = -ECONNRESET;
11444d59ad29SBart Van Assche goto out;
11459fe4bcf4SDavid Dillow
1146aef9ec39SRoland Dreier default:
11474d59ad29SBart Van Assche goto out;
1148aef9ec39SRoland Dreier }
1149aef9ec39SRoland Dreier }
11504d59ad29SBart Van Assche
11514d59ad29SBart Van Assche out:
11524d59ad29SBart Van Assche return ret <= 0 ? ret : -ENODEV;
1153aef9ec39SRoland Dreier }
1154aef9ec39SRoland Dreier
srp_inv_rkey_err_done(struct ib_cq * cq,struct ib_wc * wc)11551dc7b1f1SChristoph Hellwig static void srp_inv_rkey_err_done(struct ib_cq *cq, struct ib_wc *wc)
11561dc7b1f1SChristoph Hellwig {
11571dc7b1f1SChristoph Hellwig srp_handle_qp_err(cq, wc, "INV RKEY");
11581dc7b1f1SChristoph Hellwig }
11591dc7b1f1SChristoph Hellwig
srp_inv_rkey(struct srp_request * req,struct srp_rdma_ch * ch,u32 rkey)11601dc7b1f1SChristoph Hellwig static int srp_inv_rkey(struct srp_request *req, struct srp_rdma_ch *ch,
11611dc7b1f1SChristoph Hellwig u32 rkey)
11625cfb1782SBart Van Assche {
11635cfb1782SBart Van Assche struct ib_send_wr wr = {
11645cfb1782SBart Van Assche .opcode = IB_WR_LOCAL_INV,
11655cfb1782SBart Van Assche .next = NULL,
11665cfb1782SBart Van Assche .num_sge = 0,
11675cfb1782SBart Van Assche .send_flags = 0,
11685cfb1782SBart Van Assche .ex.invalidate_rkey = rkey,
11695cfb1782SBart Van Assche };
11705cfb1782SBart Van Assche
11711dc7b1f1SChristoph Hellwig wr.wr_cqe = &req->reg_cqe;
11721dc7b1f1SChristoph Hellwig req->reg_cqe.done = srp_inv_rkey_err_done;
117371347b0cSBart Van Assche return ib_post_send(ch->qp, &wr, NULL);
11745cfb1782SBart Van Assche }
11755cfb1782SBart Van Assche
srp_unmap_data(struct scsi_cmnd * scmnd,struct srp_rdma_ch * ch,struct srp_request * req)1176d945e1dfSRoland Dreier static void srp_unmap_data(struct scsi_cmnd *scmnd,
1177509c07bcSBart Van Assche struct srp_rdma_ch *ch,
1178d945e1dfSRoland Dreier struct srp_request *req)
1179d945e1dfSRoland Dreier {
1180509c07bcSBart Van Assche struct srp_target_port *target = ch->target;
11815cfb1782SBart Van Assche struct srp_device *dev = target->srp_host->srp_dev;
11825cfb1782SBart Van Assche struct ib_device *ibdev = dev->dev;
11835cfb1782SBart Van Assche int i, res;
11848f26c9ffSDavid Dillow
1185bb350d1dSFUJITA Tomonori if (!scsi_sglist(scmnd) ||
1186d945e1dfSRoland Dreier (scmnd->sc_data_direction != DMA_TO_DEVICE &&
1187d945e1dfSRoland Dreier scmnd->sc_data_direction != DMA_FROM_DEVICE))
1188d945e1dfSRoland Dreier return;
1189d945e1dfSRoland Dreier
11905cfb1782SBart Van Assche if (dev->use_fast_reg) {
11915cfb1782SBart Van Assche struct srp_fr_desc **pfr;
11925cfb1782SBart Van Assche
11935cfb1782SBart Van Assche for (i = req->nmdesc, pfr = req->fr_list; i > 0; i--, pfr++) {
11941dc7b1f1SChristoph Hellwig res = srp_inv_rkey(req, ch, (*pfr)->mr->rkey);
11955cfb1782SBart Van Assche if (res < 0) {
11965cfb1782SBart Van Assche shost_printk(KERN_ERR, target->scsi_host, PFX
11975cfb1782SBart Van Assche "Queueing INV WR for rkey %#x failed (%d)\n",
11985cfb1782SBart Van Assche (*pfr)->mr->rkey, res);
11995cfb1782SBart Van Assche queue_work(system_long_wq,
12005cfb1782SBart Van Assche &target->tl_err_work);
12015cfb1782SBart Van Assche }
12025cfb1782SBart Van Assche }
12035cfb1782SBart Van Assche if (req->nmdesc)
1204509c07bcSBart Van Assche srp_fr_pool_put(ch->fr_pool, req->fr_list,
12055cfb1782SBart Van Assche req->nmdesc);
12065cfb1782SBart Van Assche }
1207f5358a17SRoland Dreier
12088f26c9ffSDavid Dillow ib_dma_unmap_sg(ibdev, scsi_sglist(scmnd), scsi_sg_count(scmnd),
12098f26c9ffSDavid Dillow scmnd->sc_data_direction);
1210d945e1dfSRoland Dreier }
1211d945e1dfSRoland Dreier
121222032991SBart Van Assche /**
121322032991SBart Van Assche * srp_claim_req - Take ownership of the scmnd associated with a request.
1214509c07bcSBart Van Assche * @ch: SRP RDMA channel.
121522032991SBart Van Assche * @req: SRP request.
1216b3fe628dSBart Van Assche * @sdev: If not NULL, only take ownership for this SCSI device.
121722032991SBart Van Assche * @scmnd: If NULL, take ownership of @req->scmnd. If not NULL, only take
121822032991SBart Van Assche * ownership of @req->scmnd if it equals @scmnd.
121922032991SBart Van Assche *
122022032991SBart Van Assche * Return value:
122122032991SBart Van Assche * Either NULL or a pointer to the SCSI command the caller became owner of.
122222032991SBart Van Assche */
srp_claim_req(struct srp_rdma_ch * ch,struct srp_request * req,struct scsi_device * sdev,struct scsi_cmnd * scmnd)1223509c07bcSBart Van Assche static struct scsi_cmnd *srp_claim_req(struct srp_rdma_ch *ch,
122422032991SBart Van Assche struct srp_request *req,
1225b3fe628dSBart Van Assche struct scsi_device *sdev,
122622032991SBart Van Assche struct scsi_cmnd *scmnd)
1227526b4caaSIshai Rabinovitz {
122894a9174cSBart Van Assche unsigned long flags;
122994a9174cSBart Van Assche
1230509c07bcSBart Van Assche spin_lock_irqsave(&ch->lock, flags);
1231b3fe628dSBart Van Assche if (req->scmnd &&
1232b3fe628dSBart Van Assche (!sdev || req->scmnd->device == sdev) &&
1233b3fe628dSBart Van Assche (!scmnd || req->scmnd == scmnd)) {
123422032991SBart Van Assche scmnd = req->scmnd;
123522032991SBart Van Assche req->scmnd = NULL;
123622032991SBart Van Assche } else {
123722032991SBart Van Assche scmnd = NULL;
123822032991SBart Van Assche }
1239509c07bcSBart Van Assche spin_unlock_irqrestore(&ch->lock, flags);
124022032991SBart Van Assche
124122032991SBart Van Assche return scmnd;
124222032991SBart Van Assche }
124322032991SBart Van Assche
124422032991SBart Van Assche /**
12456ec2ba02SBart Van Assche * srp_free_req() - Unmap data and adjust ch->req_lim.
1246509c07bcSBart Van Assche * @ch: SRP RDMA channel.
1247af24663bSBart Van Assche * @req: Request to be freed.
1248af24663bSBart Van Assche * @scmnd: SCSI command associated with @req.
1249af24663bSBart Van Assche * @req_lim_delta: Amount to be added to @target->req_lim.
125022032991SBart Van Assche */
srp_free_req(struct srp_rdma_ch * ch,struct srp_request * req,struct scsi_cmnd * scmnd,s32 req_lim_delta)1251509c07bcSBart Van Assche static void srp_free_req(struct srp_rdma_ch *ch, struct srp_request *req,
1252509c07bcSBart Van Assche struct scsi_cmnd *scmnd, s32 req_lim_delta)
125322032991SBart Van Assche {
125422032991SBart Van Assche unsigned long flags;
125522032991SBart Van Assche
1256509c07bcSBart Van Assche srp_unmap_data(scmnd, ch, req);
125722032991SBart Van Assche
1258509c07bcSBart Van Assche spin_lock_irqsave(&ch->lock, flags);
1259509c07bcSBart Van Assche ch->req_lim += req_lim_delta;
1260509c07bcSBart Van Assche spin_unlock_irqrestore(&ch->lock, flags);
1261526b4caaSIshai Rabinovitz }
1262526b4caaSIshai Rabinovitz
srp_finish_req(struct srp_rdma_ch * ch,struct srp_request * req,struct scsi_device * sdev,int result)1263509c07bcSBart Van Assche static void srp_finish_req(struct srp_rdma_ch *ch, struct srp_request *req,
1264509c07bcSBart Van Assche struct scsi_device *sdev, int result)
1265526b4caaSIshai Rabinovitz {
1266509c07bcSBart Van Assche struct scsi_cmnd *scmnd = srp_claim_req(ch, req, sdev, NULL);
126722032991SBart Van Assche
126822032991SBart Van Assche if (scmnd) {
1269509c07bcSBart Van Assche srp_free_req(ch, req, scmnd, 0);
1270ed9b2264SBart Van Assche scmnd->result = result;
12715f9ae9eeSBart Van Assche scsi_done(scmnd);
127222032991SBart Van Assche }
1273526b4caaSIshai Rabinovitz }
1274526b4caaSIshai Rabinovitz
1275ad215aaeSBart Van Assche struct srp_terminate_context {
1276ad215aaeSBart Van Assche struct srp_target_port *srp_target;
1277ad215aaeSBart Van Assche int scsi_result;
1278ad215aaeSBart Van Assche };
1279ad215aaeSBart Van Assche
srp_terminate_cmd(struct scsi_cmnd * scmnd,void * context_ptr)12802dd6532eSJohn Garry static bool srp_terminate_cmd(struct scsi_cmnd *scmnd, void *context_ptr)
1281ad215aaeSBart Van Assche {
1282ad215aaeSBart Van Assche struct srp_terminate_context *context = context_ptr;
1283ad215aaeSBart Van Assche struct srp_target_port *target = context->srp_target;
12849c5274eeSBart Van Assche u32 tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmnd));
1285ad215aaeSBart Van Assche struct srp_rdma_ch *ch = &target->ch[blk_mq_unique_tag_to_hwq(tag)];
1286ad215aaeSBart Van Assche struct srp_request *req = scsi_cmd_priv(scmnd);
1287ad215aaeSBart Van Assche
1288ad215aaeSBart Van Assche srp_finish_req(ch, req, NULL, context->scsi_result);
1289ad215aaeSBart Van Assche
1290ad215aaeSBart Van Assche return true;
1291ad215aaeSBart Van Assche }
1292ad215aaeSBart Van Assche
srp_terminate_io(struct srp_rport * rport)1293ed9b2264SBart Van Assche static void srp_terminate_io(struct srp_rport *rport)
1294aef9ec39SRoland Dreier {
1295ed9b2264SBart Van Assche struct srp_target_port *target = rport->lld_data;
1296ad215aaeSBart Van Assche struct srp_terminate_context context = { .srp_target = target,
1297ad215aaeSBart Van Assche .scsi_result = DID_TRANSPORT_FAILFAST << 16 };
1298aef9ec39SRoland Dreier
1299ad215aaeSBart Van Assche scsi_host_busy_iter(target->scsi_host, srp_terminate_cmd, &context);
1300ed9b2264SBart Van Assche }
1301ed9b2264SBart Van Assche
1302513d5647SBart Van Assche /* Calculate maximum initiator to target information unit length. */
srp_max_it_iu_len(int cmd_sg_cnt,bool use_imm_data,uint32_t max_it_iu_size)1303b2e872f4SHonggang Li static uint32_t srp_max_it_iu_len(int cmd_sg_cnt, bool use_imm_data,
1304b2e872f4SHonggang Li uint32_t max_it_iu_size)
1305513d5647SBart Van Assche {
1306513d5647SBart Van Assche uint32_t max_iu_len = sizeof(struct srp_cmd) + SRP_MAX_ADD_CDB_LEN +
1307513d5647SBart Van Assche sizeof(struct srp_indirect_buf) +
1308513d5647SBart Van Assche cmd_sg_cnt * sizeof(struct srp_direct_buf);
1309513d5647SBart Van Assche
1310882981f4SBart Van Assche if (use_imm_data)
1311882981f4SBart Van Assche max_iu_len = max(max_iu_len, SRP_IMM_DATA_OFFSET +
1312882981f4SBart Van Assche srp_max_imm_data);
1313882981f4SBart Van Assche
1314b2e872f4SHonggang Li if (max_it_iu_size)
1315b2e872f4SHonggang Li max_iu_len = min(max_iu_len, max_it_iu_size);
1316b2e872f4SHonggang Li
1317b2e872f4SHonggang Li pr_debug("max_iu_len = %d\n", max_iu_len);
1318b2e872f4SHonggang Li
1319513d5647SBart Van Assche return max_iu_len;
1320513d5647SBart Van Assche }
1321513d5647SBart Van Assche
1322ed9b2264SBart Van Assche /*
1323ed9b2264SBart Van Assche * It is up to the caller to ensure that srp_rport_reconnect() calls are
1324ed9b2264SBart Van Assche * serialized and that no concurrent srp_queuecommand(), srp_abort(),
1325ed9b2264SBart Van Assche * srp_reset_device() or srp_reset_host() calls will occur while this function
1326ed9b2264SBart Van Assche * is in progress. One way to realize that is not to call this function
1327ed9b2264SBart Van Assche * directly but to call srp_reconnect_rport() instead since that last function
1328ed9b2264SBart Van Assche * serializes calls of this function via rport->mutex and also blocks
1329ed9b2264SBart Van Assche * srp_queuecommand() calls before invoking this function.
1330ed9b2264SBart Van Assche */
srp_rport_reconnect(struct srp_rport * rport)1331ed9b2264SBart Van Assche static int srp_rport_reconnect(struct srp_rport *rport)
1332ed9b2264SBart Van Assche {
1333ed9b2264SBart Van Assche struct srp_target_port *target = rport->lld_data;
1334d92c0da7SBart Van Assche struct srp_rdma_ch *ch;
1335882981f4SBart Van Assche uint32_t max_iu_len = srp_max_it_iu_len(target->cmd_sg_cnt,
1336b2e872f4SHonggang Li srp_use_imm_data,
1337b2e872f4SHonggang Li target->max_it_iu_size);
1338d92c0da7SBart Van Assche int i, j, ret = 0;
1339d92c0da7SBart Van Assche bool multich = false;
134009be70a2SBart Van Assche
1341aef9ec39SRoland Dreier srp_disconnect_target(target);
134234aa654eSBart Van Assche
134334aa654eSBart Van Assche if (target->state == SRP_TARGET_SCANNING)
134434aa654eSBart Van Assche return -ENODEV;
134534aa654eSBart Van Assche
1346aef9ec39SRoland Dreier /*
1347c7c4e7ffSBart Van Assche * Now get a new local CM ID so that we avoid confusing the target in
1348c7c4e7ffSBart Van Assche * case things are really fouled up. Doing so also ensures that all CM
1349c7c4e7ffSBart Van Assche * callbacks will have finished before a new QP is allocated.
1350aef9ec39SRoland Dreier */
1351d92c0da7SBart Van Assche for (i = 0; i < target->ch_count; i++) {
1352d92c0da7SBart Van Assche ch = &target->ch[i];
1353d92c0da7SBart Van Assche ret += srp_new_cm_id(ch);
1354d92c0da7SBart Van Assche }
1355ad215aaeSBart Van Assche {
1356ad215aaeSBart Van Assche struct srp_terminate_context context = {
1357ad215aaeSBart Van Assche .srp_target = target, .scsi_result = DID_RESET << 16};
1358509c07bcSBart Van Assche
1359ad215aaeSBart Van Assche scsi_host_busy_iter(target->scsi_host, srp_terminate_cmd,
1360ad215aaeSBart Van Assche &context);
1361d92c0da7SBart Van Assche }
1362d92c0da7SBart Van Assche for (i = 0; i < target->ch_count; i++) {
1363d92c0da7SBart Van Assche ch = &target->ch[i];
13645cfb1782SBart Van Assche /*
13655cfb1782SBart Van Assche * Whether or not creating a new CM ID succeeded, create a new
1366d92c0da7SBart Van Assche * QP. This guarantees that all completion callback function
1367d92c0da7SBart Van Assche * invocations have finished before request resetting starts.
13685cfb1782SBart Van Assche */
1369509c07bcSBart Van Assche ret += srp_create_ch_ib(ch);
13705cfb1782SBart Van Assche
1371509c07bcSBart Van Assche INIT_LIST_HEAD(&ch->free_tx);
1372d92c0da7SBart Van Assche for (j = 0; j < target->queue_size; ++j)
1373d92c0da7SBart Van Assche list_add(&ch->tx_ring[j]->list, &ch->free_tx);
1374d92c0da7SBart Van Assche }
13758de9fe3aSBart Van Assche
13768de9fe3aSBart Van Assche target->qp_in_error = false;
13778de9fe3aSBart Van Assche
1378d92c0da7SBart Van Assche for (i = 0; i < target->ch_count; i++) {
1379d92c0da7SBart Van Assche ch = &target->ch[i];
1380bbac5ccfSBart Van Assche if (ret)
1381d92c0da7SBart Van Assche break;
1382513d5647SBart Van Assche ret = srp_connect_ch(ch, max_iu_len, multich);
1383d92c0da7SBart Van Assche multich = true;
1384d92c0da7SBart Van Assche }
138509be70a2SBart Van Assche
1386ed9b2264SBart Van Assche if (ret == 0)
1387ed9b2264SBart Van Assche shost_printk(KERN_INFO, target->scsi_host,
1388ed9b2264SBart Van Assche PFX "reconnect succeeded\n");
1389aef9ec39SRoland Dreier
1390aef9ec39SRoland Dreier return ret;
1391aef9ec39SRoland Dreier }
1392aef9ec39SRoland Dreier
srp_map_desc(struct srp_map_state * state,dma_addr_t dma_addr,unsigned int dma_len,u32 rkey)13938f26c9ffSDavid Dillow static void srp_map_desc(struct srp_map_state *state, dma_addr_t dma_addr,
13948f26c9ffSDavid Dillow unsigned int dma_len, u32 rkey)
1395f5358a17SRoland Dreier {
13968f26c9ffSDavid Dillow struct srp_direct_buf *desc = state->desc;
13978f26c9ffSDavid Dillow
13983ae95da8SBart Van Assche WARN_ON_ONCE(!dma_len);
13993ae95da8SBart Van Assche
14008f26c9ffSDavid Dillow desc->va = cpu_to_be64(dma_addr);
14018f26c9ffSDavid Dillow desc->key = cpu_to_be32(rkey);
14028f26c9ffSDavid Dillow desc->len = cpu_to_be32(dma_len);
14038f26c9ffSDavid Dillow
14048f26c9ffSDavid Dillow state->total_len += dma_len;
14058f26c9ffSDavid Dillow state->desc++;
14068f26c9ffSDavid Dillow state->ndesc++;
14078f26c9ffSDavid Dillow }
14088f26c9ffSDavid Dillow
srp_reg_mr_err_done(struct ib_cq * cq,struct ib_wc * wc)14091dc7b1f1SChristoph Hellwig static void srp_reg_mr_err_done(struct ib_cq *cq, struct ib_wc *wc)
14101dc7b1f1SChristoph Hellwig {
14111dc7b1f1SChristoph Hellwig srp_handle_qp_err(cq, wc, "FAST REG");
14121dc7b1f1SChristoph Hellwig }
14131dc7b1f1SChristoph Hellwig
1414509c5f33SBart Van Assche /*
1415509c5f33SBart Van Assche * Map up to sg_nents elements of state->sg where *sg_offset_p is the offset
1416509c5f33SBart Van Assche * where to start in the first element. If sg_offset_p != NULL then
1417509c5f33SBart Van Assche * *sg_offset_p is updated to the offset in state->sg[retval] of the first
1418509c5f33SBart Van Assche * byte that has not yet been mapped.
1419509c5f33SBart Van Assche */
srp_map_finish_fr(struct srp_map_state * state,struct srp_request * req,struct srp_rdma_ch * ch,int sg_nents,unsigned int * sg_offset_p)14205cfb1782SBart Van Assche static int srp_map_finish_fr(struct srp_map_state *state,
14211dc7b1f1SChristoph Hellwig struct srp_request *req,
1422509c5f33SBart Van Assche struct srp_rdma_ch *ch, int sg_nents,
1423509c5f33SBart Van Assche unsigned int *sg_offset_p)
14245cfb1782SBart Van Assche {
1425509c07bcSBart Van Assche struct srp_target_port *target = ch->target;
14265cfb1782SBart Van Assche struct srp_device *dev = target->srp_host->srp_dev;
1427f7f7aab1SSagi Grimberg struct ib_reg_wr wr;
14285cfb1782SBart Van Assche struct srp_fr_desc *desc;
14295cfb1782SBart Van Assche u32 rkey;
1430f7f7aab1SSagi Grimberg int n, err;
14315cfb1782SBart Van Assche
1432290081b4SBart Van Assche if (state->fr.next >= state->fr.end) {
1433290081b4SBart Van Assche shost_printk(KERN_ERR, ch->target->scsi_host,
1434290081b4SBart Van Assche PFX "Out of MRs (mr_per_cmd = %d)\n",
1435290081b4SBart Van Assche ch->target->mr_per_cmd);
1436f731ed62SBart Van Assche return -ENOMEM;
1437290081b4SBart Van Assche }
1438f731ed62SBart Van Assche
143926630e8aSSagi Grimberg WARN_ON_ONCE(!dev->use_fast_reg);
144026630e8aSSagi Grimberg
1441cee687b6SBart Van Assche if (sg_nents == 1 && target->global_rkey) {
1442509c5f33SBart Van Assche unsigned int sg_offset = sg_offset_p ? *sg_offset_p : 0;
1443509c5f33SBart Van Assche
1444509c5f33SBart Van Assche srp_map_desc(state, sg_dma_address(state->sg) + sg_offset,
1445509c5f33SBart Van Assche sg_dma_len(state->sg) - sg_offset,
1446cee687b6SBart Van Assche target->global_rkey);
1447509c5f33SBart Van Assche if (sg_offset_p)
1448509c5f33SBart Van Assche *sg_offset_p = 0;
1449f7f7aab1SSagi Grimberg return 1;
145026630e8aSSagi Grimberg }
145126630e8aSSagi Grimberg
1452509c07bcSBart Van Assche desc = srp_fr_pool_get(ch->fr_pool);
14535cfb1782SBart Van Assche if (!desc)
14545cfb1782SBart Van Assche return -ENOMEM;
14555cfb1782SBart Van Assche
14565cfb1782SBart Van Assche rkey = ib_inc_rkey(desc->mr->rkey);
14575cfb1782SBart Van Assche ib_update_fast_reg_key(desc->mr, rkey);
14585cfb1782SBart Van Assche
1459509c5f33SBart Van Assche n = ib_map_mr_sg(desc->mr, state->sg, sg_nents, sg_offset_p,
1460509c5f33SBart Van Assche dev->mr_page_size);
14619d8e7d0dSBart Van Assche if (unlikely(n < 0)) {
14629d8e7d0dSBart Van Assche srp_fr_pool_put(ch->fr_pool, &desc, 1);
1463509c5f33SBart Van Assche pr_debug("%s: ib_map_mr_sg(%d, %d) returned %d.\n",
14649d8e7d0dSBart Van Assche dev_name(&req->scmnd->device->sdev_gendev), sg_nents,
1465509c5f33SBart Van Assche sg_offset_p ? *sg_offset_p : -1, n);
1466f7f7aab1SSagi Grimberg return n;
14679d8e7d0dSBart Van Assche }
14685cfb1782SBart Van Assche
1469509c5f33SBart Van Assche WARN_ON_ONCE(desc->mr->length == 0);
14705cfb1782SBart Van Assche
14711dc7b1f1SChristoph Hellwig req->reg_cqe.done = srp_reg_mr_err_done;
14721dc7b1f1SChristoph Hellwig
1473f7f7aab1SSagi Grimberg wr.wr.next = NULL;
1474f7f7aab1SSagi Grimberg wr.wr.opcode = IB_WR_REG_MR;
14751dc7b1f1SChristoph Hellwig wr.wr.wr_cqe = &req->reg_cqe;
1476f7f7aab1SSagi Grimberg wr.wr.num_sge = 0;
1477f7f7aab1SSagi Grimberg wr.wr.send_flags = 0;
1478f7f7aab1SSagi Grimberg wr.mr = desc->mr;
1479f7f7aab1SSagi Grimberg wr.key = desc->mr->rkey;
1480f7f7aab1SSagi Grimberg wr.access = (IB_ACCESS_LOCAL_WRITE |
14815cfb1782SBart Van Assche IB_ACCESS_REMOTE_READ |
14825cfb1782SBart Van Assche IB_ACCESS_REMOTE_WRITE);
14835cfb1782SBart Van Assche
1484f731ed62SBart Van Assche *state->fr.next++ = desc;
14855cfb1782SBart Van Assche state->nmdesc++;
14865cfb1782SBart Van Assche
1487f7f7aab1SSagi Grimberg srp_map_desc(state, desc->mr->iova,
1488f7f7aab1SSagi Grimberg desc->mr->length, desc->mr->rkey);
14895cfb1782SBart Van Assche
149071347b0cSBart Van Assche err = ib_post_send(ch->qp, &wr.wr, NULL);
1491509c5f33SBart Van Assche if (unlikely(err)) {
1492509c5f33SBart Van Assche WARN_ON_ONCE(err == -ENOMEM);
149326630e8aSSagi Grimberg return err;
1494509c5f33SBart Van Assche }
149526630e8aSSagi Grimberg
1496f7f7aab1SSagi Grimberg return n;
14975cfb1782SBart Van Assche }
14985cfb1782SBart Van Assche
srp_map_sg_fr(struct srp_map_state * state,struct srp_rdma_ch * ch,struct srp_request * req,struct scatterlist * scat,int count)149926630e8aSSagi Grimberg static int srp_map_sg_fr(struct srp_map_state *state, struct srp_rdma_ch *ch,
150026630e8aSSagi Grimberg struct srp_request *req, struct scatterlist *scat,
150126630e8aSSagi Grimberg int count)
150226630e8aSSagi Grimberg {
1503509c5f33SBart Van Assche unsigned int sg_offset = 0;
1504509c5f33SBart Van Assche
1505f7f7aab1SSagi Grimberg state->fr.next = req->fr_list;
1506509c5f33SBart Van Assche state->fr.end = req->fr_list + ch->target->mr_per_cmd;
1507f7f7aab1SSagi Grimberg state->sg = scat;
150826630e8aSSagi Grimberg
15093b59b7a6SBart Van Assche if (count == 0)
15103b59b7a6SBart Van Assche return 0;
15113b59b7a6SBart Van Assche
151257b0be9cSBart Van Assche while (count) {
1513f7f7aab1SSagi Grimberg int i, n;
1514f7f7aab1SSagi Grimberg
1515509c5f33SBart Van Assche n = srp_map_finish_fr(state, req, ch, count, &sg_offset);
1516f7f7aab1SSagi Grimberg if (unlikely(n < 0))
1517f7f7aab1SSagi Grimberg return n;
1518f7f7aab1SSagi Grimberg
151957b0be9cSBart Van Assche count -= n;
1520f7f7aab1SSagi Grimberg for (i = 0; i < n; i++)
1521f7f7aab1SSagi Grimberg state->sg = sg_next(state->sg);
152226630e8aSSagi Grimberg }
152326630e8aSSagi Grimberg
152426630e8aSSagi Grimberg return 0;
152526630e8aSSagi Grimberg }
152626630e8aSSagi Grimberg
srp_map_sg_dma(struct srp_map_state * state,struct srp_rdma_ch * ch,struct srp_request * req,struct scatterlist * scat,int count)152726630e8aSSagi Grimberg static int srp_map_sg_dma(struct srp_map_state *state, struct srp_rdma_ch *ch,
1528509c07bcSBart Van Assche struct srp_request *req, struct scatterlist *scat,
1529509c07bcSBart Van Assche int count)
153076bc1e1dSBart Van Assche {
1531509c07bcSBart Van Assche struct srp_target_port *target = ch->target;
153276bc1e1dSBart Van Assche struct scatterlist *sg;
153326630e8aSSagi Grimberg int i;
153476bc1e1dSBart Van Assche
15353ae95da8SBart Van Assche for_each_sg(scat, sg, count, i) {
1536a163afc8SBart Van Assche srp_map_desc(state, sg_dma_address(sg), sg_dma_len(sg),
1537cee687b6SBart Van Assche target->global_rkey);
15383ae95da8SBart Van Assche }
153976bc1e1dSBart Van Assche
154026630e8aSSagi Grimberg return 0;
154176bc1e1dSBart Van Assche }
154276bc1e1dSBart Van Assche
1543330179f2SBart Van Assche /*
1544330179f2SBart Van Assche * Register the indirect data buffer descriptor with the HCA.
1545330179f2SBart Van Assche *
1546330179f2SBart Van Assche * Note: since the indirect data buffer descriptor has been allocated with
1547330179f2SBart Van Assche * kmalloc() it is guaranteed that this buffer is a physically contiguous
1548330179f2SBart Van Assche * memory buffer.
1549330179f2SBart Van Assche */
srp_map_idb(struct srp_rdma_ch * ch,struct srp_request * req,void ** next_mr,void ** end_mr,u32 idb_len,__be32 * idb_rkey)1550330179f2SBart Van Assche static int srp_map_idb(struct srp_rdma_ch *ch, struct srp_request *req,
1551330179f2SBart Van Assche void **next_mr, void **end_mr, u32 idb_len,
1552330179f2SBart Van Assche __be32 *idb_rkey)
1553330179f2SBart Van Assche {
1554330179f2SBart Van Assche struct srp_target_port *target = ch->target;
1555330179f2SBart Van Assche struct srp_device *dev = target->srp_host->srp_dev;
1556330179f2SBart Van Assche struct srp_map_state state;
1557330179f2SBart Van Assche struct srp_direct_buf idb_desc;
1558f7f7aab1SSagi Grimberg struct scatterlist idb_sg[1];
1559330179f2SBart Van Assche int ret;
1560330179f2SBart Van Assche
1561330179f2SBart Van Assche memset(&state, 0, sizeof(state));
1562330179f2SBart Van Assche memset(&idb_desc, 0, sizeof(idb_desc));
1563330179f2SBart Van Assche state.gen.next = next_mr;
1564330179f2SBart Van Assche state.gen.end = end_mr;
1565330179f2SBart Van Assche state.desc = &idb_desc;
1566f7f7aab1SSagi Grimberg state.base_dma_addr = req->indirect_dma_addr;
1567f7f7aab1SSagi Grimberg state.dma_len = idb_len;
1568f7f7aab1SSagi Grimberg
1569f7f7aab1SSagi Grimberg if (dev->use_fast_reg) {
1570f7f7aab1SSagi Grimberg state.sg = idb_sg;
157154f5c9c5SBart Van Assche sg_init_one(idb_sg, req->indirect_desc, idb_len);
1572f7f7aab1SSagi Grimberg idb_sg->dma_address = req->indirect_dma_addr; /* hack! */
1573fc925518SChristoph Hellwig #ifdef CONFIG_NEED_SG_DMA_LENGTH
1574fc925518SChristoph Hellwig idb_sg->dma_length = idb_sg->length; /* hack^2 */
1575fc925518SChristoph Hellwig #endif
1576509c5f33SBart Van Assche ret = srp_map_finish_fr(&state, req, ch, 1, NULL);
1577f7f7aab1SSagi Grimberg if (ret < 0)
1578f7f7aab1SSagi Grimberg return ret;
1579509c5f33SBart Van Assche WARN_ON_ONCE(ret < 1);
1580f7f7aab1SSagi Grimberg } else {
1581f7f7aab1SSagi Grimberg return -EINVAL;
1582f7f7aab1SSagi Grimberg }
1583330179f2SBart Van Assche
1584330179f2SBart Van Assche *idb_rkey = idb_desc.key;
1585330179f2SBart Van Assche
1586f7f7aab1SSagi Grimberg return 0;
1587330179f2SBart Van Assche }
1588330179f2SBart Van Assche
srp_check_mapping(struct srp_map_state * state,struct srp_rdma_ch * ch,struct srp_request * req,struct scatterlist * scat,int count)1589509c5f33SBart Van Assche static void srp_check_mapping(struct srp_map_state *state,
1590509c5f33SBart Van Assche struct srp_rdma_ch *ch, struct srp_request *req,
1591509c5f33SBart Van Assche struct scatterlist *scat, int count)
1592509c5f33SBart Van Assche {
1593509c5f33SBart Van Assche struct srp_device *dev = ch->target->srp_host->srp_dev;
1594509c5f33SBart Van Assche struct srp_fr_desc **pfr;
1595509c5f33SBart Van Assche u64 desc_len = 0, mr_len = 0;
1596509c5f33SBart Van Assche int i;
1597509c5f33SBart Van Assche
1598509c5f33SBart Van Assche for (i = 0; i < state->ndesc; i++)
1599509c5f33SBart Van Assche desc_len += be32_to_cpu(req->indirect_desc[i].len);
1600509c5f33SBart Van Assche if (dev->use_fast_reg)
1601509c5f33SBart Van Assche for (i = 0, pfr = req->fr_list; i < state->nmdesc; i++, pfr++)
1602509c5f33SBart Van Assche mr_len += (*pfr)->mr->length;
1603509c5f33SBart Van Assche if (desc_len != scsi_bufflen(req->scmnd) ||
1604509c5f33SBart Van Assche mr_len > scsi_bufflen(req->scmnd))
1605509c5f33SBart Van Assche pr_err("Inconsistent: scsi len %d <> desc len %lld <> mr len %lld; ndesc %d; nmdesc = %d\n",
1606509c5f33SBart Van Assche scsi_bufflen(req->scmnd), desc_len, mr_len,
1607509c5f33SBart Van Assche state->ndesc, state->nmdesc);
1608509c5f33SBart Van Assche }
1609509c5f33SBart Van Assche
161077269cdfSBart Van Assche /**
161177269cdfSBart Van Assche * srp_map_data() - map SCSI data buffer onto an SRP request
161277269cdfSBart Van Assche * @scmnd: SCSI command to map
161377269cdfSBart Van Assche * @ch: SRP RDMA channel
161477269cdfSBart Van Assche * @req: SRP request
161577269cdfSBart Van Assche *
161677269cdfSBart Van Assche * Returns the length in bytes of the SRP_CMD IU or a negative value if
1617882981f4SBart Van Assche * mapping failed. The size of any immediate data is not included in the
1618882981f4SBart Van Assche * return value.
161977269cdfSBart Van Assche */
srp_map_data(struct scsi_cmnd * scmnd,struct srp_rdma_ch * ch,struct srp_request * req)1620509c07bcSBart Van Assche static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_rdma_ch *ch,
1621aef9ec39SRoland Dreier struct srp_request *req)
1622aef9ec39SRoland Dreier {
1623509c07bcSBart Van Assche struct srp_target_port *target = ch->target;
1624882981f4SBart Van Assche struct scatterlist *scat, *sg;
1625aef9ec39SRoland Dreier struct srp_cmd *cmd = req->cmd->buf;
1626882981f4SBart Van Assche int i, len, nents, count, ret;
162785507bccSRalph Campbell struct srp_device *dev;
162885507bccSRalph Campbell struct ib_device *ibdev;
16298f26c9ffSDavid Dillow struct srp_map_state state;
16308f26c9ffSDavid Dillow struct srp_indirect_buf *indirect_hdr;
1631882981f4SBart Van Assche u64 data_len;
1632330179f2SBart Van Assche u32 idb_len, table_len;
1633330179f2SBart Van Assche __be32 idb_rkey;
16348f26c9ffSDavid Dillow u8 fmt;
1635aef9ec39SRoland Dreier
1636882981f4SBart Van Assche req->cmd->num_sge = 1;
1637882981f4SBart Van Assche
1638bb350d1dSFUJITA Tomonori if (!scsi_sglist(scmnd) || scmnd->sc_data_direction == DMA_NONE)
1639482fffc4SBart Van Assche return sizeof(struct srp_cmd) + cmd->add_cdb_len;
1640aef9ec39SRoland Dreier
1641aef9ec39SRoland Dreier if (scmnd->sc_data_direction != DMA_FROM_DEVICE &&
1642aef9ec39SRoland Dreier scmnd->sc_data_direction != DMA_TO_DEVICE) {
16437aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host,
16447aa54bd7SDavid Dillow PFX "Unhandled data direction %d\n",
1645aef9ec39SRoland Dreier scmnd->sc_data_direction);
1646aef9ec39SRoland Dreier return -EINVAL;
1647aef9ec39SRoland Dreier }
1648aef9ec39SRoland Dreier
1649bb350d1dSFUJITA Tomonori nents = scsi_sg_count(scmnd);
1650bb350d1dSFUJITA Tomonori scat = scsi_sglist(scmnd);
1651882981f4SBart Van Assche data_len = scsi_bufflen(scmnd);
1652aef9ec39SRoland Dreier
165305321937SGreg Kroah-Hartman dev = target->srp_host->srp_dev;
165485507bccSRalph Campbell ibdev = dev->dev;
165585507bccSRalph Campbell
165685507bccSRalph Campbell count = ib_dma_map_sg(ibdev, scat, nents, scmnd->sc_data_direction);
16578f26c9ffSDavid Dillow if (unlikely(count == 0))
16588f26c9ffSDavid Dillow return -EIO;
1659aef9ec39SRoland Dreier
1660882981f4SBart Van Assche if (ch->use_imm_data &&
1661bf583470SBart Van Assche count <= ch->max_imm_sge &&
1662882981f4SBart Van Assche SRP_IMM_DATA_OFFSET + data_len <= ch->max_it_iu_len &&
1663882981f4SBart Van Assche scmnd->sc_data_direction == DMA_TO_DEVICE) {
1664882981f4SBart Van Assche struct srp_imm_buf *buf;
1665882981f4SBart Van Assche struct ib_sge *sge = &req->cmd->sge[1];
1666882981f4SBart Van Assche
1667882981f4SBart Van Assche fmt = SRP_DATA_DESC_IMM;
1668882981f4SBart Van Assche len = SRP_IMM_DATA_OFFSET;
1669882981f4SBart Van Assche req->nmdesc = 0;
1670882981f4SBart Van Assche buf = (void *)cmd->add_data + cmd->add_cdb_len;
1671882981f4SBart Van Assche buf->len = cpu_to_be32(data_len);
1672882981f4SBart Van Assche WARN_ON_ONCE((void *)(buf + 1) > (void *)cmd + len);
1673882981f4SBart Van Assche for_each_sg(scat, sg, count, i) {
1674a163afc8SBart Van Assche sge[i].addr = sg_dma_address(sg);
1675a163afc8SBart Van Assche sge[i].length = sg_dma_len(sg);
1676882981f4SBart Van Assche sge[i].lkey = target->lkey;
1677882981f4SBart Van Assche }
1678882981f4SBart Van Assche req->cmd->num_sge += count;
1679882981f4SBart Van Assche goto map_complete;
1680882981f4SBart Van Assche }
1681882981f4SBart Van Assche
1682aef9ec39SRoland Dreier fmt = SRP_DATA_DESC_DIRECT;
1683482fffc4SBart Van Assche len = sizeof(struct srp_cmd) + cmd->add_cdb_len +
1684482fffc4SBart Van Assche sizeof(struct srp_direct_buf);
1685f5358a17SRoland Dreier
1686cee687b6SBart Van Assche if (count == 1 && target->global_rkey) {
1687f5358a17SRoland Dreier /*
1688f5358a17SRoland Dreier * The midlayer only generated a single gather/scatter
1689f5358a17SRoland Dreier * entry, or DMA mapping coalesced everything to a
1690f5358a17SRoland Dreier * single entry. So a direct descriptor along with
1691f5358a17SRoland Dreier * the DMA MR suffices.
1692f5358a17SRoland Dreier */
1693482fffc4SBart Van Assche struct srp_direct_buf *buf;
1694aef9ec39SRoland Dreier
1695482fffc4SBart Van Assche buf = (void *)cmd->add_data + cmd->add_cdb_len;
1696a163afc8SBart Van Assche buf->va = cpu_to_be64(sg_dma_address(scat));
1697cee687b6SBart Van Assche buf->key = cpu_to_be32(target->global_rkey);
1698a163afc8SBart Van Assche buf->len = cpu_to_be32(sg_dma_len(scat));
16998f26c9ffSDavid Dillow
170052ede08fSBart Van Assche req->nmdesc = 0;
17018f26c9ffSDavid Dillow goto map_complete;
17028f26c9ffSDavid Dillow }
17038f26c9ffSDavid Dillow
17045cfb1782SBart Van Assche /*
17055cfb1782SBart Van Assche * We have more than one scatter/gather entry, so build our indirect
17065cfb1782SBart Van Assche * descriptor table, trying to merge as many entries as we can.
1707f5358a17SRoland Dreier */
1708482fffc4SBart Van Assche indirect_hdr = (void *)cmd->add_data + cmd->add_cdb_len;
17098f26c9ffSDavid Dillow
1710c07d424dSDavid Dillow ib_dma_sync_single_for_cpu(ibdev, req->indirect_dma_addr,
1711c07d424dSDavid Dillow target->indirect_size, DMA_TO_DEVICE);
1712c07d424dSDavid Dillow
17138f26c9ffSDavid Dillow memset(&state, 0, sizeof(state));
17149edba790SBart Van Assche state.desc = req->indirect_desc;
171526630e8aSSagi Grimberg if (dev->use_fast_reg)
1716e012f363SBart Van Assche ret = srp_map_sg_fr(&state, ch, req, scat, count);
171726630e8aSSagi Grimberg else
1718e012f363SBart Van Assche ret = srp_map_sg_dma(&state, ch, req, scat, count);
1719e012f363SBart Van Assche req->nmdesc = state.nmdesc;
1720e012f363SBart Van Assche if (ret < 0)
1721e012f363SBart Van Assche goto unmap;
17228f26c9ffSDavid Dillow
1723509c5f33SBart Van Assche {
1724509c5f33SBart Van Assche DEFINE_DYNAMIC_DEBUG_METADATA(ddm,
1725509c5f33SBart Van Assche "Memory mapping consistency check");
17261a1faf7aSBart Van Assche if (DYNAMIC_DEBUG_BRANCH(ddm))
1727509c5f33SBart Van Assche srp_check_mapping(&state, ch, req, scat, count);
1728509c5f33SBart Van Assche }
17298f26c9ffSDavid Dillow
1730c07d424dSDavid Dillow /* We've mapped the request, now pull as much of the indirect
1731c07d424dSDavid Dillow * descriptor table as we can into the command buffer. If this
1732c07d424dSDavid Dillow * target is not using an external indirect table, we are
1733c07d424dSDavid Dillow * guaranteed to fit into the command, as the SCSI layer won't
1734c07d424dSDavid Dillow * give us more S/G entries than we allow.
17358f26c9ffSDavid Dillow */
17368f26c9ffSDavid Dillow if (state.ndesc == 1) {
17375cfb1782SBart Van Assche /*
17385cfb1782SBart Van Assche * Memory registration collapsed the sg-list into one entry,
17398f26c9ffSDavid Dillow * so use a direct descriptor.
17408f26c9ffSDavid Dillow */
1741482fffc4SBart Van Assche struct srp_direct_buf *buf;
17428f26c9ffSDavid Dillow
1743482fffc4SBart Van Assche buf = (void *)cmd->add_data + cmd->add_cdb_len;
1744c07d424dSDavid Dillow *buf = req->indirect_desc[0];
17458f26c9ffSDavid Dillow goto map_complete;
17468f26c9ffSDavid Dillow }
17478f26c9ffSDavid Dillow
1748c07d424dSDavid Dillow if (unlikely(target->cmd_sg_cnt < state.ndesc &&
1749c07d424dSDavid Dillow !target->allow_ext_sg)) {
1750c07d424dSDavid Dillow shost_printk(KERN_ERR, target->scsi_host,
1751c07d424dSDavid Dillow "Could not fit S/G list into SRP_CMD\n");
1752e012f363SBart Van Assche ret = -EIO;
1753e012f363SBart Van Assche goto unmap;
1754c07d424dSDavid Dillow }
1755c07d424dSDavid Dillow
1756c07d424dSDavid Dillow count = min(state.ndesc, target->cmd_sg_cnt);
17578f26c9ffSDavid Dillow table_len = state.ndesc * sizeof (struct srp_direct_buf);
1758330179f2SBart Van Assche idb_len = sizeof(struct srp_indirect_buf) + table_len;
1759aef9ec39SRoland Dreier
1760aef9ec39SRoland Dreier fmt = SRP_DATA_DESC_INDIRECT;
1761482fffc4SBart Van Assche len = sizeof(struct srp_cmd) + cmd->add_cdb_len +
1762482fffc4SBart Van Assche sizeof(struct srp_indirect_buf);
1763c07d424dSDavid Dillow len += count * sizeof (struct srp_direct_buf);
1764f5358a17SRoland Dreier
1765c07d424dSDavid Dillow memcpy(indirect_hdr->desc_list, req->indirect_desc,
1766c07d424dSDavid Dillow count * sizeof (struct srp_direct_buf));
176785507bccSRalph Campbell
1768cee687b6SBart Van Assche if (!target->global_rkey) {
1769330179f2SBart Van Assche ret = srp_map_idb(ch, req, state.gen.next, state.gen.end,
1770330179f2SBart Van Assche idb_len, &idb_rkey);
1771330179f2SBart Van Assche if (ret < 0)
1772e012f363SBart Van Assche goto unmap;
1773330179f2SBart Van Assche req->nmdesc++;
1774330179f2SBart Van Assche } else {
1775cee687b6SBart Van Assche idb_rkey = cpu_to_be32(target->global_rkey);
1776330179f2SBart Van Assche }
1777330179f2SBart Van Assche
1778c07d424dSDavid Dillow indirect_hdr->table_desc.va = cpu_to_be64(req->indirect_dma_addr);
1779330179f2SBart Van Assche indirect_hdr->table_desc.key = idb_rkey;
17808f26c9ffSDavid Dillow indirect_hdr->table_desc.len = cpu_to_be32(table_len);
17818f26c9ffSDavid Dillow indirect_hdr->len = cpu_to_be32(state.total_len);
1782aef9ec39SRoland Dreier
1783aef9ec39SRoland Dreier if (scmnd->sc_data_direction == DMA_TO_DEVICE)
1784c07d424dSDavid Dillow cmd->data_out_desc_cnt = count;
1785aef9ec39SRoland Dreier else
1786c07d424dSDavid Dillow cmd->data_in_desc_cnt = count;
1787c07d424dSDavid Dillow
1788c07d424dSDavid Dillow ib_dma_sync_single_for_device(ibdev, req->indirect_dma_addr, table_len,
1789c07d424dSDavid Dillow DMA_TO_DEVICE);
1790aef9ec39SRoland Dreier
17918f26c9ffSDavid Dillow map_complete:
1792aef9ec39SRoland Dreier if (scmnd->sc_data_direction == DMA_TO_DEVICE)
1793aef9ec39SRoland Dreier cmd->buf_fmt = fmt << 4;
1794aef9ec39SRoland Dreier else
1795aef9ec39SRoland Dreier cmd->buf_fmt = fmt;
1796aef9ec39SRoland Dreier
1797aef9ec39SRoland Dreier return len;
1798e012f363SBart Van Assche
1799e012f363SBart Van Assche unmap:
1800e012f363SBart Van Assche srp_unmap_data(scmnd, ch, req);
1801ffc548bbSBart Van Assche if (ret == -ENOMEM && req->nmdesc >= target->mr_pool_size)
1802ffc548bbSBart Van Assche ret = -E2BIG;
1803e012f363SBart Van Assche return ret;
1804aef9ec39SRoland Dreier }
1805aef9ec39SRoland Dreier
180605a1d750SDavid Dillow /*
180776c75b25SBart Van Assche * Return an IU and possible credit to the free pool
180876c75b25SBart Van Assche */
srp_put_tx_iu(struct srp_rdma_ch * ch,struct srp_iu * iu,enum srp_iu_type iu_type)1809509c07bcSBart Van Assche static void srp_put_tx_iu(struct srp_rdma_ch *ch, struct srp_iu *iu,
181076c75b25SBart Van Assche enum srp_iu_type iu_type)
181176c75b25SBart Van Assche {
181276c75b25SBart Van Assche unsigned long flags;
181376c75b25SBart Van Assche
1814509c07bcSBart Van Assche spin_lock_irqsave(&ch->lock, flags);
1815509c07bcSBart Van Assche list_add(&iu->list, &ch->free_tx);
181676c75b25SBart Van Assche if (iu_type != SRP_IU_RSP)
1817509c07bcSBart Van Assche ++ch->req_lim;
1818509c07bcSBart Van Assche spin_unlock_irqrestore(&ch->lock, flags);
181976c75b25SBart Van Assche }
182076c75b25SBart Van Assche
182176c75b25SBart Van Assche /*
1822509c07bcSBart Van Assche * Must be called with ch->lock held to protect req_lim and free_tx.
1823e9684678SBart Van Assche * If IU is not sent, it must be returned using srp_put_tx_iu().
182405a1d750SDavid Dillow *
182505a1d750SDavid Dillow * Note:
182605a1d750SDavid Dillow * An upper limit for the number of allocated information units for each
182705a1d750SDavid Dillow * request type is:
182805a1d750SDavid Dillow * - SRP_IU_CMD: SRP_CMD_SQ_SIZE, since the SCSI mid-layer never queues
182905a1d750SDavid Dillow * more than Scsi_Host.can_queue requests.
183005a1d750SDavid Dillow * - SRP_IU_TSK_MGMT: SRP_TSK_MGMT_SQ_SIZE.
183105a1d750SDavid Dillow * - SRP_IU_RSP: 1, since a conforming SRP target never sends more than
183205a1d750SDavid Dillow * one unanswered SRP request to an initiator.
183305a1d750SDavid Dillow */
__srp_get_tx_iu(struct srp_rdma_ch * ch,enum srp_iu_type iu_type)1834509c07bcSBart Van Assche static struct srp_iu *__srp_get_tx_iu(struct srp_rdma_ch *ch,
183505a1d750SDavid Dillow enum srp_iu_type iu_type)
183605a1d750SDavid Dillow {
1837509c07bcSBart Van Assche struct srp_target_port *target = ch->target;
183805a1d750SDavid Dillow s32 rsv = (iu_type == SRP_IU_TSK_MGMT) ? 0 : SRP_TSK_MGMT_SQ_SIZE;
183905a1d750SDavid Dillow struct srp_iu *iu;
184005a1d750SDavid Dillow
184193c76dbbSBart Van Assche lockdep_assert_held(&ch->lock);
184293c76dbbSBart Van Assche
18431dc7b1f1SChristoph Hellwig ib_process_cq_direct(ch->send_cq, -1);
184405a1d750SDavid Dillow
1845509c07bcSBart Van Assche if (list_empty(&ch->free_tx))
184605a1d750SDavid Dillow return NULL;
184705a1d750SDavid Dillow
184805a1d750SDavid Dillow /* Initiator responses to target requests do not consume credits */
184976c75b25SBart Van Assche if (iu_type != SRP_IU_RSP) {
1850509c07bcSBart Van Assche if (ch->req_lim <= rsv) {
185105a1d750SDavid Dillow ++target->zero_req_lim;
185205a1d750SDavid Dillow return NULL;
185305a1d750SDavid Dillow }
185405a1d750SDavid Dillow
1855509c07bcSBart Van Assche --ch->req_lim;
185676c75b25SBart Van Assche }
185776c75b25SBart Van Assche
1858509c07bcSBart Van Assche iu = list_first_entry(&ch->free_tx, struct srp_iu, list);
185976c75b25SBart Van Assche list_del(&iu->list);
186005a1d750SDavid Dillow return iu;
186105a1d750SDavid Dillow }
186205a1d750SDavid Dillow
18639294000dSBart Van Assche /*
18649294000dSBart Van Assche * Note: if this function is called from inside ib_drain_sq() then it will
18659294000dSBart Van Assche * be called without ch->lock being held. If ib_drain_sq() dequeues a WQE
18669294000dSBart Van Assche * with status IB_WC_SUCCESS then that's a bug.
18679294000dSBart Van Assche */
srp_send_done(struct ib_cq * cq,struct ib_wc * wc)18681dc7b1f1SChristoph Hellwig static void srp_send_done(struct ib_cq *cq, struct ib_wc *wc)
18691dc7b1f1SChristoph Hellwig {
18701dc7b1f1SChristoph Hellwig struct srp_iu *iu = container_of(wc->wr_cqe, struct srp_iu, cqe);
18711dc7b1f1SChristoph Hellwig struct srp_rdma_ch *ch = cq->cq_context;
18721dc7b1f1SChristoph Hellwig
18731dc7b1f1SChristoph Hellwig if (unlikely(wc->status != IB_WC_SUCCESS)) {
18741dc7b1f1SChristoph Hellwig srp_handle_qp_err(cq, wc, "SEND");
18751dc7b1f1SChristoph Hellwig return;
18761dc7b1f1SChristoph Hellwig }
18771dc7b1f1SChristoph Hellwig
187893c76dbbSBart Van Assche lockdep_assert_held(&ch->lock);
187993c76dbbSBart Van Assche
18801dc7b1f1SChristoph Hellwig list_add(&iu->list, &ch->free_tx);
18811dc7b1f1SChristoph Hellwig }
18821dc7b1f1SChristoph Hellwig
1883882981f4SBart Van Assche /**
1884882981f4SBart Van Assche * srp_post_send() - send an SRP information unit
1885882981f4SBart Van Assche * @ch: RDMA channel over which to send the information unit.
1886882981f4SBart Van Assche * @iu: Information unit to send.
1887882981f4SBart Van Assche * @len: Length of the information unit excluding immediate data.
1888882981f4SBart Van Assche */
srp_post_send(struct srp_rdma_ch * ch,struct srp_iu * iu,int len)1889509c07bcSBart Van Assche static int srp_post_send(struct srp_rdma_ch *ch, struct srp_iu *iu, int len)
189005a1d750SDavid Dillow {
1891509c07bcSBart Van Assche struct srp_target_port *target = ch->target;
189271347b0cSBart Van Assche struct ib_send_wr wr;
189305a1d750SDavid Dillow
1894882981f4SBart Van Assche if (WARN_ON_ONCE(iu->num_sge > SRP_MAX_SGE))
1895882981f4SBart Van Assche return -EINVAL;
1896882981f4SBart Van Assche
1897882981f4SBart Van Assche iu->sge[0].addr = iu->dma;
1898882981f4SBart Van Assche iu->sge[0].length = len;
1899882981f4SBart Van Assche iu->sge[0].lkey = target->lkey;
190005a1d750SDavid Dillow
19011dc7b1f1SChristoph Hellwig iu->cqe.done = srp_send_done;
19021dc7b1f1SChristoph Hellwig
190305a1d750SDavid Dillow wr.next = NULL;
19041dc7b1f1SChristoph Hellwig wr.wr_cqe = &iu->cqe;
1905882981f4SBart Van Assche wr.sg_list = &iu->sge[0];
1906882981f4SBart Van Assche wr.num_sge = iu->num_sge;
190705a1d750SDavid Dillow wr.opcode = IB_WR_SEND;
190805a1d750SDavid Dillow wr.send_flags = IB_SEND_SIGNALED;
190905a1d750SDavid Dillow
191071347b0cSBart Van Assche return ib_post_send(ch->qp, &wr, NULL);
191105a1d750SDavid Dillow }
191205a1d750SDavid Dillow
srp_post_recv(struct srp_rdma_ch * ch,struct srp_iu * iu)1913509c07bcSBart Van Assche static int srp_post_recv(struct srp_rdma_ch *ch, struct srp_iu *iu)
1914c996bb47SBart Van Assche {
1915509c07bcSBart Van Assche struct srp_target_port *target = ch->target;
191671347b0cSBart Van Assche struct ib_recv_wr wr;
1917dcb4cb85SBart Van Assche struct ib_sge list;
1918c996bb47SBart Van Assche
1919c996bb47SBart Van Assche list.addr = iu->dma;
1920c996bb47SBart Van Assche list.length = iu->size;
19219af76271SDavid Dillow list.lkey = target->lkey;
1922c996bb47SBart Van Assche
19231dc7b1f1SChristoph Hellwig iu->cqe.done = srp_recv_done;
19241dc7b1f1SChristoph Hellwig
1925c996bb47SBart Van Assche wr.next = NULL;
19261dc7b1f1SChristoph Hellwig wr.wr_cqe = &iu->cqe;
1927c996bb47SBart Van Assche wr.sg_list = &list;
1928c996bb47SBart Van Assche wr.num_sge = 1;
1929c996bb47SBart Van Assche
193071347b0cSBart Van Assche return ib_post_recv(ch->qp, &wr, NULL);
1931c996bb47SBart Van Assche }
1932c996bb47SBart Van Assche
srp_process_rsp(struct srp_rdma_ch * ch,struct srp_rsp * rsp)1933509c07bcSBart Van Assche static void srp_process_rsp(struct srp_rdma_ch *ch, struct srp_rsp *rsp)
1934aef9ec39SRoland Dreier {
1935509c07bcSBart Van Assche struct srp_target_port *target = ch->target;
1936aef9ec39SRoland Dreier struct srp_request *req;
1937aef9ec39SRoland Dreier struct scsi_cmnd *scmnd;
1938aef9ec39SRoland Dreier unsigned long flags;
1939aef9ec39SRoland Dreier
1940aef9ec39SRoland Dreier if (unlikely(rsp->tag & SRP_TAG_TSK_MGMT)) {
1941509c07bcSBart Van Assche spin_lock_irqsave(&ch->lock, flags);
1942509c07bcSBart Van Assche ch->req_lim += be32_to_cpu(rsp->req_lim_delta);
19430a6fdbdeSBart Van Assche if (rsp->tag == ch->tsk_mgmt_tag) {
1944509c07bcSBart Van Assche ch->tsk_mgmt_status = -1;
1945f8b6e31eSDavid Dillow if (be32_to_cpu(rsp->resp_data_len) >= 4)
1946509c07bcSBart Van Assche ch->tsk_mgmt_status = rsp->data[3];
1947509c07bcSBart Van Assche complete(&ch->tsk_mgmt_done);
1948aef9ec39SRoland Dreier } else {
19490a6fdbdeSBart Van Assche shost_printk(KERN_ERR, target->scsi_host,
19500a6fdbdeSBart Van Assche "Received tsk mgmt response too late for tag %#llx\n",
19510a6fdbdeSBart Van Assche rsp->tag);
19520a6fdbdeSBart Van Assche }
19530a6fdbdeSBart Van Assche spin_unlock_irqrestore(&ch->lock, flags);
19540a6fdbdeSBart Van Assche } else {
195577f2c1a4SBart Van Assche scmnd = scsi_host_find_tag(target->scsi_host, rsp->tag);
1956ad215aaeSBart Van Assche if (scmnd) {
1957ad215aaeSBart Van Assche req = scsi_cmd_priv(scmnd);
195877f2c1a4SBart Van Assche scmnd = srp_claim_req(ch, req, NULL, scmnd);
195912f35199Syangx.jy@fujitsu.com }
196012f35199Syangx.jy@fujitsu.com if (!scmnd) {
19617aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host,
1962d92c0da7SBart Van Assche "Null scmnd for RSP w/tag %#016llx received on ch %td / QP %#x\n",
1963d92c0da7SBart Van Assche rsp->tag, ch - target->ch, ch->qp->qp_num);
196422032991SBart Van Assche
1965509c07bcSBart Van Assche spin_lock_irqsave(&ch->lock, flags);
1966509c07bcSBart Van Assche ch->req_lim += be32_to_cpu(rsp->req_lim_delta);
1967509c07bcSBart Van Assche spin_unlock_irqrestore(&ch->lock, flags);
196822032991SBart Van Assche
196922032991SBart Van Assche return;
197022032991SBart Van Assche }
1971aef9ec39SRoland Dreier scmnd->result = rsp->status;
1972aef9ec39SRoland Dreier
1973aef9ec39SRoland Dreier if (rsp->flags & SRP_RSP_FLAG_SNSVALID) {
1974aef9ec39SRoland Dreier memcpy(scmnd->sense_buffer, rsp->data +
1975aef9ec39SRoland Dreier be32_to_cpu(rsp->resp_data_len),
1976aef9ec39SRoland Dreier min_t(int, be32_to_cpu(rsp->sense_data_len),
1977aef9ec39SRoland Dreier SCSI_SENSE_BUFFERSIZE));
1978aef9ec39SRoland Dreier }
1979aef9ec39SRoland Dreier
1980e714531aSBart Van Assche if (unlikely(rsp->flags & SRP_RSP_FLAG_DIUNDER))
1981bb350d1dSFUJITA Tomonori scsi_set_resid(scmnd, be32_to_cpu(rsp->data_in_res_cnt));
1982e714531aSBart Van Assche else if (unlikely(rsp->flags & SRP_RSP_FLAG_DOUNDER))
1983e714531aSBart Van Assche scsi_set_resid(scmnd, be32_to_cpu(rsp->data_out_res_cnt));
1984aef9ec39SRoland Dreier
1985509c07bcSBart Van Assche srp_free_req(ch, req, scmnd,
198622032991SBart Van Assche be32_to_cpu(rsp->req_lim_delta));
198722032991SBart Van Assche
19885f9ae9eeSBart Van Assche scsi_done(scmnd);
1989aef9ec39SRoland Dreier }
1990aef9ec39SRoland Dreier }
1991aef9ec39SRoland Dreier
srp_response_common(struct srp_rdma_ch * ch,s32 req_delta,void * rsp,int len)1992509c07bcSBart Van Assche static int srp_response_common(struct srp_rdma_ch *ch, s32 req_delta,
1993bb12588aSDavid Dillow void *rsp, int len)
1994bb12588aSDavid Dillow {
1995509c07bcSBart Van Assche struct srp_target_port *target = ch->target;
199676c75b25SBart Van Assche struct ib_device *dev = target->srp_host->srp_dev->dev;
1997bb12588aSDavid Dillow unsigned long flags;
1998bb12588aSDavid Dillow struct srp_iu *iu;
199976c75b25SBart Van Assche int err;
2000bb12588aSDavid Dillow
2001509c07bcSBart Van Assche spin_lock_irqsave(&ch->lock, flags);
2002509c07bcSBart Van Assche ch->req_lim += req_delta;
2003509c07bcSBart Van Assche iu = __srp_get_tx_iu(ch, SRP_IU_RSP);
2004509c07bcSBart Van Assche spin_unlock_irqrestore(&ch->lock, flags);
200576c75b25SBart Van Assche
2006bb12588aSDavid Dillow if (!iu) {
2007bb12588aSDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX
2008bb12588aSDavid Dillow "no IU available to send response\n");
200976c75b25SBart Van Assche return 1;
2010bb12588aSDavid Dillow }
2011bb12588aSDavid Dillow
2012882981f4SBart Van Assche iu->num_sge = 1;
2013bb12588aSDavid Dillow ib_dma_sync_single_for_cpu(dev, iu->dma, len, DMA_TO_DEVICE);
2014bb12588aSDavid Dillow memcpy(iu->buf, rsp, len);
2015bb12588aSDavid Dillow ib_dma_sync_single_for_device(dev, iu->dma, len, DMA_TO_DEVICE);
2016bb12588aSDavid Dillow
2017509c07bcSBart Van Assche err = srp_post_send(ch, iu, len);
201876c75b25SBart Van Assche if (err) {
2019bb12588aSDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX
2020bb12588aSDavid Dillow "unable to post response: %d\n", err);
2021509c07bcSBart Van Assche srp_put_tx_iu(ch, iu, SRP_IU_RSP);
202276c75b25SBart Van Assche }
2023bb12588aSDavid Dillow
2024bb12588aSDavid Dillow return err;
2025bb12588aSDavid Dillow }
2026bb12588aSDavid Dillow
srp_process_cred_req(struct srp_rdma_ch * ch,struct srp_cred_req * req)2027509c07bcSBart Van Assche static void srp_process_cred_req(struct srp_rdma_ch *ch,
2028bb12588aSDavid Dillow struct srp_cred_req *req)
2029bb12588aSDavid Dillow {
2030bb12588aSDavid Dillow struct srp_cred_rsp rsp = {
2031bb12588aSDavid Dillow .opcode = SRP_CRED_RSP,
2032bb12588aSDavid Dillow .tag = req->tag,
2033bb12588aSDavid Dillow };
2034bb12588aSDavid Dillow s32 delta = be32_to_cpu(req->req_lim_delta);
2035bb12588aSDavid Dillow
2036509c07bcSBart Van Assche if (srp_response_common(ch, delta, &rsp, sizeof(rsp)))
2037509c07bcSBart Van Assche shost_printk(KERN_ERR, ch->target->scsi_host, PFX
2038bb12588aSDavid Dillow "problems processing SRP_CRED_REQ\n");
2039bb12588aSDavid Dillow }
2040bb12588aSDavid Dillow
srp_process_aer_req(struct srp_rdma_ch * ch,struct srp_aer_req * req)2041509c07bcSBart Van Assche static void srp_process_aer_req(struct srp_rdma_ch *ch,
2042bb12588aSDavid Dillow struct srp_aer_req *req)
2043bb12588aSDavid Dillow {
2044509c07bcSBart Van Assche struct srp_target_port *target = ch->target;
2045bb12588aSDavid Dillow struct srp_aer_rsp rsp = {
2046bb12588aSDavid Dillow .opcode = SRP_AER_RSP,
2047bb12588aSDavid Dillow .tag = req->tag,
2048bb12588aSDavid Dillow };
2049bb12588aSDavid Dillow s32 delta = be32_to_cpu(req->req_lim_delta);
2050bb12588aSDavid Dillow
2051bb12588aSDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX
2052985aa495SBart Van Assche "ignoring AER for LUN %llu\n", scsilun_to_int(&req->lun));
2053bb12588aSDavid Dillow
2054509c07bcSBart Van Assche if (srp_response_common(ch, delta, &rsp, sizeof(rsp)))
2055bb12588aSDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX
2056bb12588aSDavid Dillow "problems processing SRP_AER_REQ\n");
2057bb12588aSDavid Dillow }
2058bb12588aSDavid Dillow
srp_recv_done(struct ib_cq * cq,struct ib_wc * wc)20591dc7b1f1SChristoph Hellwig static void srp_recv_done(struct ib_cq *cq, struct ib_wc *wc)
2060aef9ec39SRoland Dreier {
20611dc7b1f1SChristoph Hellwig struct srp_iu *iu = container_of(wc->wr_cqe, struct srp_iu, cqe);
20621dc7b1f1SChristoph Hellwig struct srp_rdma_ch *ch = cq->cq_context;
2063509c07bcSBart Van Assche struct srp_target_port *target = ch->target;
2064dcb4cb85SBart Van Assche struct ib_device *dev = target->srp_host->srp_dev->dev;
2065c996bb47SBart Van Assche int res;
2066aef9ec39SRoland Dreier u8 opcode;
2067aef9ec39SRoland Dreier
20681dc7b1f1SChristoph Hellwig if (unlikely(wc->status != IB_WC_SUCCESS)) {
20691dc7b1f1SChristoph Hellwig srp_handle_qp_err(cq, wc, "RECV");
20701dc7b1f1SChristoph Hellwig return;
20711dc7b1f1SChristoph Hellwig }
20721dc7b1f1SChristoph Hellwig
2073509c07bcSBart Van Assche ib_dma_sync_single_for_cpu(dev, iu->dma, ch->max_ti_iu_len,
207485507bccSRalph Campbell DMA_FROM_DEVICE);
2075aef9ec39SRoland Dreier
2076aef9ec39SRoland Dreier opcode = *(u8 *) iu->buf;
2077aef9ec39SRoland Dreier
2078aef9ec39SRoland Dreier if (0) {
20797aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host,
20807aa54bd7SDavid Dillow PFX "recv completion, opcode 0x%02x\n", opcode);
20817a700811SBart Van Assche print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 8, 1,
20827a700811SBart Van Assche iu->buf, wc->byte_len, true);
2083aef9ec39SRoland Dreier }
2084aef9ec39SRoland Dreier
2085aef9ec39SRoland Dreier switch (opcode) {
2086aef9ec39SRoland Dreier case SRP_RSP:
2087509c07bcSBart Van Assche srp_process_rsp(ch, iu->buf);
2088aef9ec39SRoland Dreier break;
2089aef9ec39SRoland Dreier
2090bb12588aSDavid Dillow case SRP_CRED_REQ:
2091509c07bcSBart Van Assche srp_process_cred_req(ch, iu->buf);
2092bb12588aSDavid Dillow break;
2093bb12588aSDavid Dillow
2094bb12588aSDavid Dillow case SRP_AER_REQ:
2095509c07bcSBart Van Assche srp_process_aer_req(ch, iu->buf);
2096bb12588aSDavid Dillow break;
2097bb12588aSDavid Dillow
2098aef9ec39SRoland Dreier case SRP_T_LOGOUT:
2099aef9ec39SRoland Dreier /* XXX Handle target logout */
21007aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host,
21017aa54bd7SDavid Dillow PFX "Got target logout request\n");
2102aef9ec39SRoland Dreier break;
2103aef9ec39SRoland Dreier
2104aef9ec39SRoland Dreier default:
21057aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host,
21067aa54bd7SDavid Dillow PFX "Unhandled SRP opcode 0x%02x\n", opcode);
2107aef9ec39SRoland Dreier break;
2108aef9ec39SRoland Dreier }
2109aef9ec39SRoland Dreier
2110509c07bcSBart Van Assche ib_dma_sync_single_for_device(dev, iu->dma, ch->max_ti_iu_len,
211185507bccSRalph Campbell DMA_FROM_DEVICE);
2112c996bb47SBart Van Assche
2113509c07bcSBart Van Assche res = srp_post_recv(ch, iu);
2114c996bb47SBart Van Assche if (res != 0)
2115c996bb47SBart Van Assche shost_printk(KERN_ERR, target->scsi_host,
2116c996bb47SBart Van Assche PFX "Recv failed with error code %d\n", res);
2117aef9ec39SRoland Dreier }
2118aef9ec39SRoland Dreier
2119c1120f89SBart Van Assche /**
2120c1120f89SBart Van Assche * srp_tl_err_work() - handle a transport layer error
2121af24663bSBart Van Assche * @work: Work structure embedded in an SRP target port.
2122c1120f89SBart Van Assche *
2123c1120f89SBart Van Assche * Note: This function may get invoked before the rport has been created,
2124c1120f89SBart Van Assche * hence the target->rport test.
2125c1120f89SBart Van Assche */
srp_tl_err_work(struct work_struct * work)2126c1120f89SBart Van Assche static void srp_tl_err_work(struct work_struct *work)
2127c1120f89SBart Van Assche {
2128c1120f89SBart Van Assche struct srp_target_port *target;
2129c1120f89SBart Van Assche
2130c1120f89SBart Van Assche target = container_of(work, struct srp_target_port, tl_err_work);
2131c1120f89SBart Van Assche if (target->rport)
2132c1120f89SBart Van Assche srp_start_tl_fail_timers(target->rport);
2133c1120f89SBart Van Assche }
2134c1120f89SBart Van Assche
srp_handle_qp_err(struct ib_cq * cq,struct ib_wc * wc,const char * opname)21351dc7b1f1SChristoph Hellwig static void srp_handle_qp_err(struct ib_cq *cq, struct ib_wc *wc,
21361dc7b1f1SChristoph Hellwig const char *opname)
2137948d1e88SBart Van Assche {
21381dc7b1f1SChristoph Hellwig struct srp_rdma_ch *ch = cq->cq_context;
21397dad6b2eSBart Van Assche struct srp_target_port *target = ch->target;
21407dad6b2eSBart Van Assche
2141c014c8cdSBart Van Assche if (ch->connected && !target->qp_in_error) {
21425cfb1782SBart Van Assche shost_printk(KERN_ERR, target->scsi_host,
21431dc7b1f1SChristoph Hellwig PFX "failed %s status %s (%d) for CQE %p\n",
21441dc7b1f1SChristoph Hellwig opname, ib_wc_status_msg(wc->status), wc->status,
21451dc7b1f1SChristoph Hellwig wc->wr_cqe);
2146c1120f89SBart Van Assche queue_work(system_long_wq, &target->tl_err_work);
21474f0af697SBart Van Assche }
2148948d1e88SBart Van Assche target->qp_in_error = true;
2149948d1e88SBart Van Assche }
2150948d1e88SBart Van Assche
srp_queuecommand(struct Scsi_Host * shost,struct scsi_cmnd * scmnd)215176c75b25SBart Van Assche static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd)
2152aef9ec39SRoland Dreier {
21539c5274eeSBart Van Assche struct request *rq = scsi_cmd_to_rq(scmnd);
215476c75b25SBart Van Assche struct srp_target_port *target = host_to_target(shost);
2155509c07bcSBart Van Assche struct srp_rdma_ch *ch;
2156ad215aaeSBart Van Assche struct srp_request *req = scsi_cmd_priv(scmnd);
2157aef9ec39SRoland Dreier struct srp_iu *iu;
2158aef9ec39SRoland Dreier struct srp_cmd *cmd;
215985507bccSRalph Campbell struct ib_device *dev;
216076c75b25SBart Van Assche unsigned long flags;
216177f2c1a4SBart Van Assche u32 tag;
2162d1b4289eSBart Van Assche int len, ret;
2163aef9ec39SRoland Dreier
2164d1b4289eSBart Van Assche scmnd->result = srp_chkready(target->rport);
2165d1b4289eSBart Van Assche if (unlikely(scmnd->result))
2166d1b4289eSBart Van Assche goto err;
21672ce19e72SBart Van Assche
21689c5274eeSBart Van Assche WARN_ON_ONCE(rq->tag < 0);
21699c5274eeSBart Van Assche tag = blk_mq_unique_tag(rq);
2170d92c0da7SBart Van Assche ch = &target->ch[blk_mq_unique_tag_to_hwq(tag)];
2171509c07bcSBart Van Assche
2172509c07bcSBart Van Assche spin_lock_irqsave(&ch->lock, flags);
2173509c07bcSBart Van Assche iu = __srp_get_tx_iu(ch, SRP_IU_CMD);
2174509c07bcSBart Van Assche spin_unlock_irqrestore(&ch->lock, flags);
2175aef9ec39SRoland Dreier
217677f2c1a4SBart Van Assche if (!iu)
217777f2c1a4SBart Van Assche goto err;
217877f2c1a4SBart Van Assche
217905321937SGreg Kroah-Hartman dev = target->srp_host->srp_dev->dev;
2180513d5647SBart Van Assche ib_dma_sync_single_for_cpu(dev, iu->dma, ch->max_it_iu_len,
218185507bccSRalph Campbell DMA_TO_DEVICE);
2182aef9ec39SRoland Dreier
2183aef9ec39SRoland Dreier cmd = iu->buf;
2184aef9ec39SRoland Dreier memset(cmd, 0, sizeof *cmd);
2185aef9ec39SRoland Dreier
2186aef9ec39SRoland Dreier cmd->opcode = SRP_CMD;
2187985aa495SBart Van Assche int_to_scsilun(scmnd->device->lun, &cmd->lun);
218877f2c1a4SBart Van Assche cmd->tag = tag;
2189aef9ec39SRoland Dreier memcpy(cmd->cdb, scmnd->cmnd, scmnd->cmd_len);
2190482fffc4SBart Van Assche if (unlikely(scmnd->cmd_len > sizeof(cmd->cdb))) {
2191482fffc4SBart Van Assche cmd->add_cdb_len = round_up(scmnd->cmd_len - sizeof(cmd->cdb),
2192482fffc4SBart Van Assche 4);
2193482fffc4SBart Van Assche if (WARN_ON_ONCE(cmd->add_cdb_len > SRP_MAX_ADD_CDB_LEN))
2194482fffc4SBart Van Assche goto err_iu;
2195482fffc4SBart Van Assche }
2196aef9ec39SRoland Dreier
2197aef9ec39SRoland Dreier req->scmnd = scmnd;
2198aef9ec39SRoland Dreier req->cmd = iu;
2199aef9ec39SRoland Dreier
2200509c07bcSBart Van Assche len = srp_map_data(scmnd, ch, req);
2201aef9ec39SRoland Dreier if (len < 0) {
22027aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host,
2203d1b4289eSBart Van Assche PFX "Failed to map data (%d)\n", len);
2204d1b4289eSBart Van Assche /*
2205d1b4289eSBart Van Assche * If we ran out of memory descriptors (-ENOMEM) because an
2206d1b4289eSBart Van Assche * application is queuing many requests with more than
220752ede08fSBart Van Assche * max_pages_per_mr sg-list elements, tell the SCSI mid-layer
2208d1b4289eSBart Van Assche * to reduce queue depth temporarily.
2209d1b4289eSBart Van Assche */
2210d1b4289eSBart Van Assche scmnd->result = len == -ENOMEM ?
22113d45cefcSHannes Reinecke DID_OK << 16 | SAM_STAT_TASK_SET_FULL : DID_ERROR << 16;
221276c75b25SBart Van Assche goto err_iu;
2213aef9ec39SRoland Dreier }
2214aef9ec39SRoland Dreier
2215513d5647SBart Van Assche ib_dma_sync_single_for_device(dev, iu->dma, ch->max_it_iu_len,
221685507bccSRalph Campbell DMA_TO_DEVICE);
2217aef9ec39SRoland Dreier
2218509c07bcSBart Van Assche if (srp_post_send(ch, iu, len)) {
22197aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX "Send failed\n");
22202ee00f6aSBart Van Assche scmnd->result = DID_ERROR << 16;
2221aef9ec39SRoland Dreier goto err_unmap;
2222aef9ec39SRoland Dreier }
2223aef9ec39SRoland Dreier
2224fd561412SBart Van Assche return 0;
2225aef9ec39SRoland Dreier
2226aef9ec39SRoland Dreier err_unmap:
2227509c07bcSBart Van Assche srp_unmap_data(scmnd, ch, req);
2228aef9ec39SRoland Dreier
222976c75b25SBart Van Assche err_iu:
2230509c07bcSBart Van Assche srp_put_tx_iu(ch, iu, SRP_IU_CMD);
223176c75b25SBart Van Assche
2232024ca901SBart Van Assche /*
2233024ca901SBart Van Assche * Avoid that the loops that iterate over the request ring can
2234024ca901SBart Van Assche * encounter a dangling SCSI command pointer.
2235024ca901SBart Van Assche */
2236024ca901SBart Van Assche req->scmnd = NULL;
2237024ca901SBart Van Assche
2238d1b4289eSBart Van Assche err:
2239d1b4289eSBart Van Assche if (scmnd->result) {
22405f9ae9eeSBart Van Assche scsi_done(scmnd);
2241d1b4289eSBart Van Assche ret = 0;
2242d1b4289eSBart Van Assche } else {
2243d1b4289eSBart Van Assche ret = SCSI_MLQUEUE_HOST_BUSY;
2244d1b4289eSBart Van Assche }
2245a95cadb9SBart Van Assche
2246fd561412SBart Van Assche return ret;
2247aef9ec39SRoland Dreier }
2248aef9ec39SRoland Dreier
22494d73f95fSBart Van Assche /*
22504d73f95fSBart Van Assche * Note: the resources allocated in this function are freed in
2251509c07bcSBart Van Assche * srp_free_ch_ib().
22524d73f95fSBart Van Assche */
srp_alloc_iu_bufs(struct srp_rdma_ch * ch)2253509c07bcSBart Van Assche static int srp_alloc_iu_bufs(struct srp_rdma_ch *ch)
2254aef9ec39SRoland Dreier {
2255509c07bcSBart Van Assche struct srp_target_port *target = ch->target;
2256aef9ec39SRoland Dreier int i;
2257aef9ec39SRoland Dreier
2258509c07bcSBart Van Assche ch->rx_ring = kcalloc(target->queue_size, sizeof(*ch->rx_ring),
22594d73f95fSBart Van Assche GFP_KERNEL);
2260509c07bcSBart Van Assche if (!ch->rx_ring)
22614d73f95fSBart Van Assche goto err_no_ring;
2262509c07bcSBart Van Assche ch->tx_ring = kcalloc(target->queue_size, sizeof(*ch->tx_ring),
22634d73f95fSBart Van Assche GFP_KERNEL);
2264509c07bcSBart Van Assche if (!ch->tx_ring)
22654d73f95fSBart Van Assche goto err_no_ring;
22664d73f95fSBart Van Assche
22674d73f95fSBart Van Assche for (i = 0; i < target->queue_size; ++i) {
2268509c07bcSBart Van Assche ch->rx_ring[i] = srp_alloc_iu(target->srp_host,
2269509c07bcSBart Van Assche ch->max_ti_iu_len,
2270aef9ec39SRoland Dreier GFP_KERNEL, DMA_FROM_DEVICE);
2271509c07bcSBart Van Assche if (!ch->rx_ring[i])
2272aef9ec39SRoland Dreier goto err;
2273aef9ec39SRoland Dreier }
2274aef9ec39SRoland Dreier
22754d73f95fSBart Van Assche for (i = 0; i < target->queue_size; ++i) {
2276509c07bcSBart Van Assche ch->tx_ring[i] = srp_alloc_iu(target->srp_host,
2277513d5647SBart Van Assche ch->max_it_iu_len,
2278aef9ec39SRoland Dreier GFP_KERNEL, DMA_TO_DEVICE);
2279509c07bcSBart Van Assche if (!ch->tx_ring[i])
2280aef9ec39SRoland Dreier goto err;
2281dcb4cb85SBart Van Assche
2282509c07bcSBart Van Assche list_add(&ch->tx_ring[i]->list, &ch->free_tx);
2283aef9ec39SRoland Dreier }
2284aef9ec39SRoland Dreier
2285aef9ec39SRoland Dreier return 0;
2286aef9ec39SRoland Dreier
2287aef9ec39SRoland Dreier err:
22884d73f95fSBart Van Assche for (i = 0; i < target->queue_size; ++i) {
2289509c07bcSBart Van Assche srp_free_iu(target->srp_host, ch->rx_ring[i]);
2290509c07bcSBart Van Assche srp_free_iu(target->srp_host, ch->tx_ring[i]);
2291aef9ec39SRoland Dreier }
2292aef9ec39SRoland Dreier
22934d73f95fSBart Van Assche
22944d73f95fSBart Van Assche err_no_ring:
2295509c07bcSBart Van Assche kfree(ch->tx_ring);
2296509c07bcSBart Van Assche ch->tx_ring = NULL;
2297509c07bcSBart Van Assche kfree(ch->rx_ring);
2298509c07bcSBart Van Assche ch->rx_ring = NULL;
2299aef9ec39SRoland Dreier
2300aef9ec39SRoland Dreier return -ENOMEM;
2301aef9ec39SRoland Dreier }
2302aef9ec39SRoland Dreier
srp_compute_rq_tmo(struct ib_qp_attr * qp_attr,int attr_mask)2303c9b03c1aSBart Van Assche static uint32_t srp_compute_rq_tmo(struct ib_qp_attr *qp_attr, int attr_mask)
2304c9b03c1aSBart Van Assche {
2305c9b03c1aSBart Van Assche uint64_t T_tr_ns, max_compl_time_ms;
2306c9b03c1aSBart Van Assche uint32_t rq_tmo_jiffies;
2307c9b03c1aSBart Van Assche
2308c9b03c1aSBart Van Assche /*
2309c9b03c1aSBart Van Assche * According to section 11.2.4.2 in the IBTA spec (Modify Queue Pair,
2310c9b03c1aSBart Van Assche * table 91), both the QP timeout and the retry count have to be set
2311c9b03c1aSBart Van Assche * for RC QP's during the RTR to RTS transition.
2312c9b03c1aSBart Van Assche */
2313c9b03c1aSBart Van Assche WARN_ON_ONCE((attr_mask & (IB_QP_TIMEOUT | IB_QP_RETRY_CNT)) !=
2314c9b03c1aSBart Van Assche (IB_QP_TIMEOUT | IB_QP_RETRY_CNT));
2315c9b03c1aSBart Van Assche
2316c9b03c1aSBart Van Assche /*
2317c9b03c1aSBart Van Assche * Set target->rq_tmo_jiffies to one second more than the largest time
2318c9b03c1aSBart Van Assche * it can take before an error completion is generated. See also
2319c9b03c1aSBart Van Assche * C9-140..142 in the IBTA spec for more information about how to
2320c9b03c1aSBart Van Assche * convert the QP Local ACK Timeout value to nanoseconds.
2321c9b03c1aSBart Van Assche */
2322c9b03c1aSBart Van Assche T_tr_ns = 4096 * (1ULL << qp_attr->timeout);
2323c9b03c1aSBart Van Assche max_compl_time_ms = qp_attr->retry_cnt * 4 * T_tr_ns;
2324c9b03c1aSBart Van Assche do_div(max_compl_time_ms, NSEC_PER_MSEC);
2325c9b03c1aSBart Van Assche rq_tmo_jiffies = msecs_to_jiffies(max_compl_time_ms + 1000);
2326c9b03c1aSBart Van Assche
2327c9b03c1aSBart Van Assche return rq_tmo_jiffies;
2328c9b03c1aSBart Van Assche }
2329c9b03c1aSBart Van Assche
srp_cm_rep_handler(struct ib_cm_id * cm_id,const struct srp_login_rsp * lrsp,struct srp_rdma_ch * ch)2330961e0be8SDavid Dillow static void srp_cm_rep_handler(struct ib_cm_id *cm_id,
2331e6300cbdSBart Van Assche const struct srp_login_rsp *lrsp,
2332509c07bcSBart Van Assche struct srp_rdma_ch *ch)
2333961e0be8SDavid Dillow {
2334509c07bcSBart Van Assche struct srp_target_port *target = ch->target;
2335961e0be8SDavid Dillow struct ib_qp_attr *qp_attr = NULL;
2336961e0be8SDavid Dillow int attr_mask = 0;
233719f31343SBart Van Assche int ret = 0;
2338961e0be8SDavid Dillow int i;
2339961e0be8SDavid Dillow
2340961e0be8SDavid Dillow if (lrsp->opcode == SRP_LOGIN_RSP) {
2341509c07bcSBart Van Assche ch->max_ti_iu_len = be32_to_cpu(lrsp->max_ti_iu_len);
2342509c07bcSBart Van Assche ch->req_lim = be32_to_cpu(lrsp->req_lim_delta);
23430fbb37ddSSergey Gorenko ch->use_imm_data = srp_use_imm_data &&
23440fbb37ddSSergey Gorenko (lrsp->rsp_flags & SRP_LOGIN_RSP_IMMED_SUPP);
2345882981f4SBart Van Assche ch->max_it_iu_len = srp_max_it_iu_len(target->cmd_sg_cnt,
2346b2e872f4SHonggang Li ch->use_imm_data,
2347b2e872f4SHonggang Li target->max_it_iu_size);
2348513d5647SBart Van Assche WARN_ON_ONCE(ch->max_it_iu_len >
2349513d5647SBart Van Assche be32_to_cpu(lrsp->max_it_iu_len));
2350961e0be8SDavid Dillow
2351882981f4SBart Van Assche if (ch->use_imm_data)
2352882981f4SBart Van Assche shost_printk(KERN_DEBUG, target->scsi_host,
2353882981f4SBart Van Assche PFX "using immediate data\n");
2354961e0be8SDavid Dillow
2355961e0be8SDavid Dillow /*
2356961e0be8SDavid Dillow * Reserve credits for task management so we don't
2357961e0be8SDavid Dillow * bounce requests back to the SCSI mid-layer.
2358961e0be8SDavid Dillow */
2359961e0be8SDavid Dillow target->scsi_host->can_queue
2360509c07bcSBart Van Assche = min(ch->req_lim - SRP_TSK_MGMT_SQ_SIZE,
2361961e0be8SDavid Dillow target->scsi_host->can_queue);
23624d73f95fSBart Van Assche target->scsi_host->cmd_per_lun
23634d73f95fSBart Van Assche = min_t(int, target->scsi_host->can_queue,
23644d73f95fSBart Van Assche target->scsi_host->cmd_per_lun);
2365961e0be8SDavid Dillow } else {
2366961e0be8SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host,
2367961e0be8SDavid Dillow PFX "Unhandled RSP opcode %#x\n", lrsp->opcode);
2368961e0be8SDavid Dillow ret = -ECONNRESET;
2369961e0be8SDavid Dillow goto error;
2370961e0be8SDavid Dillow }
2371961e0be8SDavid Dillow
2372509c07bcSBart Van Assche if (!ch->rx_ring) {
2373509c07bcSBart Van Assche ret = srp_alloc_iu_bufs(ch);
2374961e0be8SDavid Dillow if (ret)
2375961e0be8SDavid Dillow goto error;
2376961e0be8SDavid Dillow }
2377961e0be8SDavid Dillow
237819f31343SBart Van Assche for (i = 0; i < target->queue_size; i++) {
237919f31343SBart Van Assche struct srp_iu *iu = ch->rx_ring[i];
238019f31343SBart Van Assche
238119f31343SBart Van Assche ret = srp_post_recv(ch, iu);
238219f31343SBart Van Assche if (ret)
238319f31343SBart Van Assche goto error;
238419f31343SBart Van Assche }
238519f31343SBart Van Assche
238619f31343SBart Van Assche if (!target->using_rdma_cm) {
2387961e0be8SDavid Dillow ret = -ENOMEM;
238819f31343SBart Van Assche qp_attr = kmalloc(sizeof(*qp_attr), GFP_KERNEL);
2389961e0be8SDavid Dillow if (!qp_attr)
2390961e0be8SDavid Dillow goto error;
2391961e0be8SDavid Dillow
2392961e0be8SDavid Dillow qp_attr->qp_state = IB_QPS_RTR;
2393961e0be8SDavid Dillow ret = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask);
2394961e0be8SDavid Dillow if (ret)
2395961e0be8SDavid Dillow goto error_free;
2396961e0be8SDavid Dillow
2397509c07bcSBart Van Assche ret = ib_modify_qp(ch->qp, qp_attr, attr_mask);
2398961e0be8SDavid Dillow if (ret)
2399961e0be8SDavid Dillow goto error_free;
2400961e0be8SDavid Dillow
2401961e0be8SDavid Dillow qp_attr->qp_state = IB_QPS_RTS;
2402961e0be8SDavid Dillow ret = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask);
2403961e0be8SDavid Dillow if (ret)
2404961e0be8SDavid Dillow goto error_free;
2405961e0be8SDavid Dillow
2406c9b03c1aSBart Van Assche target->rq_tmo_jiffies = srp_compute_rq_tmo(qp_attr, attr_mask);
2407c9b03c1aSBart Van Assche
2408509c07bcSBart Van Assche ret = ib_modify_qp(ch->qp, qp_attr, attr_mask);
2409961e0be8SDavid Dillow if (ret)
2410961e0be8SDavid Dillow goto error_free;
2411961e0be8SDavid Dillow
2412961e0be8SDavid Dillow ret = ib_send_cm_rtu(cm_id, NULL, 0);
241319f31343SBart Van Assche }
2414961e0be8SDavid Dillow
2415961e0be8SDavid Dillow error_free:
2416961e0be8SDavid Dillow kfree(qp_attr);
2417961e0be8SDavid Dillow
2418961e0be8SDavid Dillow error:
2419509c07bcSBart Van Assche ch->status = ret;
2420961e0be8SDavid Dillow }
2421961e0be8SDavid Dillow
srp_ib_cm_rej_handler(struct ib_cm_id * cm_id,const struct ib_cm_event * event,struct srp_rdma_ch * ch)242219f31343SBart Van Assche static void srp_ib_cm_rej_handler(struct ib_cm_id *cm_id,
2423e7ff98aeSParav Pandit const struct ib_cm_event *event,
2424509c07bcSBart Van Assche struct srp_rdma_ch *ch)
2425aef9ec39SRoland Dreier {
2426509c07bcSBart Van Assche struct srp_target_port *target = ch->target;
24277aa54bd7SDavid Dillow struct Scsi_Host *shost = target->scsi_host;
2428aef9ec39SRoland Dreier struct ib_class_port_info *cpi;
2429aef9ec39SRoland Dreier int opcode;
243019f31343SBart Van Assche u16 dlid;
2431aef9ec39SRoland Dreier
2432aef9ec39SRoland Dreier switch (event->param.rej_rcvd.reason) {
2433aef9ec39SRoland Dreier case IB_CM_REJ_PORT_CM_REDIRECT:
2434aef9ec39SRoland Dreier cpi = event->param.rej_rcvd.ari;
243519f31343SBart Van Assche dlid = be16_to_cpu(cpi->redirect_lid);
243619f31343SBart Van Assche sa_path_set_dlid(&ch->ib_cm.path, dlid);
243719f31343SBart Van Assche ch->ib_cm.path.pkey = cpi->redirect_pkey;
2438aef9ec39SRoland Dreier cm_id->remote_cm_qpn = be32_to_cpu(cpi->redirect_qp) & 0x00ffffff;
243919f31343SBart Van Assche memcpy(ch->ib_cm.path.dgid.raw, cpi->redirect_gid, 16);
2440aef9ec39SRoland Dreier
244119f31343SBart Van Assche ch->status = dlid ? SRP_DLID_REDIRECT : SRP_PORT_REDIRECT;
2442aef9ec39SRoland Dreier break;
2443aef9ec39SRoland Dreier
2444aef9ec39SRoland Dreier case IB_CM_REJ_PORT_REDIRECT:
24455d7cbfd6SRoland Dreier if (srp_target_is_topspin(target)) {
244619f31343SBart Van Assche union ib_gid *dgid = &ch->ib_cm.path.dgid;
244719f31343SBart Van Assche
2448aef9ec39SRoland Dreier /*
2449aef9ec39SRoland Dreier * Topspin/Cisco SRP gateways incorrectly send
2450aef9ec39SRoland Dreier * reject reason code 25 when they mean 24
2451aef9ec39SRoland Dreier * (port redirect).
2452aef9ec39SRoland Dreier */
245319f31343SBart Van Assche memcpy(dgid->raw, event->param.rej_rcvd.ari, 16);
2454aef9ec39SRoland Dreier
24557aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, shost,
24567aa54bd7SDavid Dillow PFX "Topspin/Cisco redirect to target port GID %016llx%016llx\n",
245719f31343SBart Van Assche be64_to_cpu(dgid->global.subnet_prefix),
245819f31343SBart Van Assche be64_to_cpu(dgid->global.interface_id));
2459aef9ec39SRoland Dreier
2460509c07bcSBart Van Assche ch->status = SRP_PORT_REDIRECT;
2461aef9ec39SRoland Dreier } else {
24627aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost,
24637aa54bd7SDavid Dillow " REJ reason: IB_CM_REJ_PORT_REDIRECT\n");
2464509c07bcSBart Van Assche ch->status = -ECONNRESET;
2465aef9ec39SRoland Dreier }
2466aef9ec39SRoland Dreier break;
2467aef9ec39SRoland Dreier
2468aef9ec39SRoland Dreier case IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID:
24697aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost,
24707aa54bd7SDavid Dillow " REJ reason: IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID\n");
2471509c07bcSBart Van Assche ch->status = -ECONNRESET;
2472aef9ec39SRoland Dreier break;
2473aef9ec39SRoland Dreier
2474aef9ec39SRoland Dreier case IB_CM_REJ_CONSUMER_DEFINED:
2475aef9ec39SRoland Dreier opcode = *(u8 *) event->private_data;
2476aef9ec39SRoland Dreier if (opcode == SRP_LOGIN_REJ) {
2477aef9ec39SRoland Dreier struct srp_login_rej *rej = event->private_data;
2478aef9ec39SRoland Dreier u32 reason = be32_to_cpu(rej->reason);
2479aef9ec39SRoland Dreier
2480aef9ec39SRoland Dreier if (reason == SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE)
24817aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost,
24827aa54bd7SDavid Dillow PFX "SRP_LOGIN_REJ: requested max_it_iu_len too large\n");
2483aef9ec39SRoland Dreier else
2484e7ffde01SBart Van Assche shost_printk(KERN_WARNING, shost, PFX
2485e7ffde01SBart Van Assche "SRP LOGIN from %pI6 to %pI6 REJECTED, reason 0x%08x\n",
2486747fe000SBart Van Assche target->sgid.raw,
248719f31343SBart Van Assche target->ib_cm.orig_dgid.raw,
248819f31343SBart Van Assche reason);
2489aef9ec39SRoland Dreier } else
24907aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost,
24917aa54bd7SDavid Dillow " REJ reason: IB_CM_REJ_CONSUMER_DEFINED,"
2492aef9ec39SRoland Dreier " opcode 0x%02x\n", opcode);
2493509c07bcSBart Van Assche ch->status = -ECONNRESET;
2494aef9ec39SRoland Dreier break;
2495aef9ec39SRoland Dreier
24969fe4bcf4SDavid Dillow case IB_CM_REJ_STALE_CONN:
24979fe4bcf4SDavid Dillow shost_printk(KERN_WARNING, shost, " REJ reason: stale connection\n");
2498509c07bcSBart Van Assche ch->status = SRP_STALE_CONN;
24999fe4bcf4SDavid Dillow break;
25009fe4bcf4SDavid Dillow
2501aef9ec39SRoland Dreier default:
25027aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, " REJ reason 0x%x\n",
2503aef9ec39SRoland Dreier event->param.rej_rcvd.reason);
2504509c07bcSBart Van Assche ch->status = -ECONNRESET;
2505aef9ec39SRoland Dreier }
2506aef9ec39SRoland Dreier }
2507aef9ec39SRoland Dreier
srp_ib_cm_handler(struct ib_cm_id * cm_id,const struct ib_cm_event * event)2508e7ff98aeSParav Pandit static int srp_ib_cm_handler(struct ib_cm_id *cm_id,
2509e7ff98aeSParav Pandit const struct ib_cm_event *event)
2510aef9ec39SRoland Dreier {
2511509c07bcSBart Van Assche struct srp_rdma_ch *ch = cm_id->context;
2512509c07bcSBart Van Assche struct srp_target_port *target = ch->target;
2513aef9ec39SRoland Dreier int comp = 0;
2514aef9ec39SRoland Dreier
2515aef9ec39SRoland Dreier switch (event->event) {
2516aef9ec39SRoland Dreier case IB_CM_REQ_ERROR:
25177aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, target->scsi_host,
25187aa54bd7SDavid Dillow PFX "Sending CM REQ failed\n");
2519aef9ec39SRoland Dreier comp = 1;
2520509c07bcSBart Van Assche ch->status = -ECONNRESET;
2521aef9ec39SRoland Dreier break;
2522aef9ec39SRoland Dreier
2523aef9ec39SRoland Dreier case IB_CM_REP_RECEIVED:
2524aef9ec39SRoland Dreier comp = 1;
2525509c07bcSBart Van Assche srp_cm_rep_handler(cm_id, event->private_data, ch);
2526aef9ec39SRoland Dreier break;
2527aef9ec39SRoland Dreier
2528aef9ec39SRoland Dreier case IB_CM_REJ_RECEIVED:
25297aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, target->scsi_host, PFX "REJ received\n");
2530aef9ec39SRoland Dreier comp = 1;
2531aef9ec39SRoland Dreier
253219f31343SBart Van Assche srp_ib_cm_rej_handler(cm_id, event, ch);
2533aef9ec39SRoland Dreier break;
2534aef9ec39SRoland Dreier
2535b7ac4ab4SIshai Rabinovitz case IB_CM_DREQ_RECEIVED:
25367aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host,
25377aa54bd7SDavid Dillow PFX "DREQ received - connection closed\n");
2538c014c8cdSBart Van Assche ch->connected = false;
2539b7ac4ab4SIshai Rabinovitz if (ib_send_cm_drep(cm_id, NULL, 0))
25407aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host,
25417aa54bd7SDavid Dillow PFX "Sending CM DREP failed\n");
2542c1120f89SBart Van Assche queue_work(system_long_wq, &target->tl_err_work);
2543aef9ec39SRoland Dreier break;
2544aef9ec39SRoland Dreier
2545aef9ec39SRoland Dreier case IB_CM_TIMEWAIT_EXIT:
25467aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host,
25477aa54bd7SDavid Dillow PFX "connection closed\n");
2548ac72d766SBart Van Assche comp = 1;
2549aef9ec39SRoland Dreier
2550509c07bcSBart Van Assche ch->status = 0;
2551aef9ec39SRoland Dreier break;
2552aef9ec39SRoland Dreier
2553b7ac4ab4SIshai Rabinovitz case IB_CM_MRA_RECEIVED:
2554b7ac4ab4SIshai Rabinovitz case IB_CM_DREQ_ERROR:
2555b7ac4ab4SIshai Rabinovitz case IB_CM_DREP_RECEIVED:
2556b7ac4ab4SIshai Rabinovitz break;
2557b7ac4ab4SIshai Rabinovitz
2558aef9ec39SRoland Dreier default:
25597aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host,
25607aa54bd7SDavid Dillow PFX "Unhandled CM event %d\n", event->event);
2561aef9ec39SRoland Dreier break;
2562aef9ec39SRoland Dreier }
2563aef9ec39SRoland Dreier
2564aef9ec39SRoland Dreier if (comp)
2565509c07bcSBart Van Assche complete(&ch->done);
2566aef9ec39SRoland Dreier
2567aef9ec39SRoland Dreier return 0;
2568aef9ec39SRoland Dreier }
2569aef9ec39SRoland Dreier
srp_rdma_cm_rej_handler(struct srp_rdma_ch * ch,struct rdma_cm_event * event)257019f31343SBart Van Assche static void srp_rdma_cm_rej_handler(struct srp_rdma_ch *ch,
257119f31343SBart Van Assche struct rdma_cm_event *event)
257219f31343SBart Van Assche {
257319f31343SBart Van Assche struct srp_target_port *target = ch->target;
257419f31343SBart Van Assche struct Scsi_Host *shost = target->scsi_host;
257519f31343SBart Van Assche int opcode;
257619f31343SBart Van Assche
257719f31343SBart Van Assche switch (event->status) {
257819f31343SBart Van Assche case IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID:
257919f31343SBart Van Assche shost_printk(KERN_WARNING, shost,
258019f31343SBart Van Assche " REJ reason: IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID\n");
258119f31343SBart Van Assche ch->status = -ECONNRESET;
258219f31343SBart Van Assche break;
258319f31343SBart Van Assche
258419f31343SBart Van Assche case IB_CM_REJ_CONSUMER_DEFINED:
258519f31343SBart Van Assche opcode = *(u8 *) event->param.conn.private_data;
258619f31343SBart Van Assche if (opcode == SRP_LOGIN_REJ) {
258719f31343SBart Van Assche struct srp_login_rej *rej =
258819f31343SBart Van Assche (struct srp_login_rej *)
258919f31343SBart Van Assche event->param.conn.private_data;
259019f31343SBart Van Assche u32 reason = be32_to_cpu(rej->reason);
259119f31343SBart Van Assche
259219f31343SBart Van Assche if (reason == SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE)
259319f31343SBart Van Assche shost_printk(KERN_WARNING, shost,
259419f31343SBart Van Assche PFX "SRP_LOGIN_REJ: requested max_it_iu_len too large\n");
259519f31343SBart Van Assche else
259619f31343SBart Van Assche shost_printk(KERN_WARNING, shost,
259719f31343SBart Van Assche PFX "SRP LOGIN REJECTED, reason 0x%08x\n", reason);
259819f31343SBart Van Assche } else {
259919f31343SBart Van Assche shost_printk(KERN_WARNING, shost,
260019f31343SBart Van Assche " REJ reason: IB_CM_REJ_CONSUMER_DEFINED, opcode 0x%02x\n",
260119f31343SBart Van Assche opcode);
260219f31343SBart Van Assche }
260319f31343SBart Van Assche ch->status = -ECONNRESET;
260419f31343SBart Van Assche break;
260519f31343SBart Van Assche
260619f31343SBart Van Assche case IB_CM_REJ_STALE_CONN:
260719f31343SBart Van Assche shost_printk(KERN_WARNING, shost,
260819f31343SBart Van Assche " REJ reason: stale connection\n");
260919f31343SBart Van Assche ch->status = SRP_STALE_CONN;
261019f31343SBart Van Assche break;
261119f31343SBart Van Assche
261219f31343SBart Van Assche default:
261319f31343SBart Van Assche shost_printk(KERN_WARNING, shost, " REJ reason 0x%x\n",
261419f31343SBart Van Assche event->status);
261519f31343SBart Van Assche ch->status = -ECONNRESET;
261619f31343SBart Van Assche break;
261719f31343SBart Van Assche }
261819f31343SBart Van Assche }
261919f31343SBart Van Assche
srp_rdma_cm_handler(struct rdma_cm_id * cm_id,struct rdma_cm_event * event)262019f31343SBart Van Assche static int srp_rdma_cm_handler(struct rdma_cm_id *cm_id,
262119f31343SBart Van Assche struct rdma_cm_event *event)
262219f31343SBart Van Assche {
262319f31343SBart Van Assche struct srp_rdma_ch *ch = cm_id->context;
262419f31343SBart Van Assche struct srp_target_port *target = ch->target;
262519f31343SBart Van Assche int comp = 0;
262619f31343SBart Van Assche
262719f31343SBart Van Assche switch (event->event) {
262819f31343SBart Van Assche case RDMA_CM_EVENT_ADDR_RESOLVED:
262919f31343SBart Van Assche ch->status = 0;
263019f31343SBart Van Assche comp = 1;
263119f31343SBart Van Assche break;
263219f31343SBart Van Assche
263319f31343SBart Van Assche case RDMA_CM_EVENT_ADDR_ERROR:
263419f31343SBart Van Assche ch->status = -ENXIO;
263519f31343SBart Van Assche comp = 1;
263619f31343SBart Van Assche break;
263719f31343SBart Van Assche
263819f31343SBart Van Assche case RDMA_CM_EVENT_ROUTE_RESOLVED:
263919f31343SBart Van Assche ch->status = 0;
264019f31343SBart Van Assche comp = 1;
264119f31343SBart Van Assche break;
264219f31343SBart Van Assche
264319f31343SBart Van Assche case RDMA_CM_EVENT_ROUTE_ERROR:
264419f31343SBart Van Assche case RDMA_CM_EVENT_UNREACHABLE:
264519f31343SBart Van Assche ch->status = -EHOSTUNREACH;
264619f31343SBart Van Assche comp = 1;
264719f31343SBart Van Assche break;
264819f31343SBart Van Assche
264919f31343SBart Van Assche case RDMA_CM_EVENT_CONNECT_ERROR:
265019f31343SBart Van Assche shost_printk(KERN_DEBUG, target->scsi_host,
265119f31343SBart Van Assche PFX "Sending CM REQ failed\n");
265219f31343SBart Van Assche comp = 1;
265319f31343SBart Van Assche ch->status = -ECONNRESET;
265419f31343SBart Van Assche break;
265519f31343SBart Van Assche
265619f31343SBart Van Assche case RDMA_CM_EVENT_ESTABLISHED:
265719f31343SBart Van Assche comp = 1;
265819f31343SBart Van Assche srp_cm_rep_handler(NULL, event->param.conn.private_data, ch);
265919f31343SBart Van Assche break;
266019f31343SBart Van Assche
266119f31343SBart Van Assche case RDMA_CM_EVENT_REJECTED:
266219f31343SBart Van Assche shost_printk(KERN_DEBUG, target->scsi_host, PFX "REJ received\n");
266319f31343SBart Van Assche comp = 1;
266419f31343SBart Van Assche
266519f31343SBart Van Assche srp_rdma_cm_rej_handler(ch, event);
266619f31343SBart Van Assche break;
266719f31343SBart Van Assche
266819f31343SBart Van Assche case RDMA_CM_EVENT_DISCONNECTED:
266919f31343SBart Van Assche if (ch->connected) {
267019f31343SBart Van Assche shost_printk(KERN_WARNING, target->scsi_host,
267119f31343SBart Van Assche PFX "received DREQ\n");
267219f31343SBart Van Assche rdma_disconnect(ch->rdma_cm.cm_id);
267319f31343SBart Van Assche comp = 1;
267419f31343SBart Van Assche ch->status = 0;
267519f31343SBart Van Assche queue_work(system_long_wq, &target->tl_err_work);
267619f31343SBart Van Assche }
267719f31343SBart Van Assche break;
267819f31343SBart Van Assche
267919f31343SBart Van Assche case RDMA_CM_EVENT_TIMEWAIT_EXIT:
268019f31343SBart Van Assche shost_printk(KERN_ERR, target->scsi_host,
268119f31343SBart Van Assche PFX "connection closed\n");
268219f31343SBart Van Assche
268319f31343SBart Van Assche comp = 1;
268419f31343SBart Van Assche ch->status = 0;
268519f31343SBart Van Assche break;
268619f31343SBart Van Assche
268719f31343SBart Van Assche default:
268819f31343SBart Van Assche shost_printk(KERN_WARNING, target->scsi_host,
268919f31343SBart Van Assche PFX "Unhandled CM event %d\n", event->event);
269019f31343SBart Van Assche break;
269119f31343SBart Van Assche }
269219f31343SBart Van Assche
269319f31343SBart Van Assche if (comp)
269419f31343SBart Van Assche complete(&ch->done);
269519f31343SBart Van Assche
269619f31343SBart Van Assche return 0;
269719f31343SBart Van Assche }
269819f31343SBart Van Assche
269971444b97SJack Wang /**
270071444b97SJack Wang * srp_change_queue_depth - setting device queue depth
270171444b97SJack Wang * @sdev: scsi device struct
270271444b97SJack Wang * @qdepth: requested queue depth
270371444b97SJack Wang *
270471444b97SJack Wang * Returns queue depth.
270571444b97SJack Wang */
270671444b97SJack Wang static int
srp_change_queue_depth(struct scsi_device * sdev,int qdepth)2707db5ed4dfSChristoph Hellwig srp_change_queue_depth(struct scsi_device *sdev, int qdepth)
270871444b97SJack Wang {
270971444b97SJack Wang if (!sdev->tagged_supported)
27101e6f2416SChristoph Hellwig qdepth = 1;
2711db5ed4dfSChristoph Hellwig return scsi_change_queue_depth(sdev, qdepth);
271271444b97SJack Wang }
271371444b97SJack Wang
srp_send_tsk_mgmt(struct srp_rdma_ch * ch,u64 req_tag,u64 lun,u8 func,u8 * status)2714985aa495SBart Van Assche static int srp_send_tsk_mgmt(struct srp_rdma_ch *ch, u64 req_tag, u64 lun,
27150a6fdbdeSBart Van Assche u8 func, u8 *status)
2716aef9ec39SRoland Dreier {
2717509c07bcSBart Van Assche struct srp_target_port *target = ch->target;
2718a95cadb9SBart Van Assche struct srp_rport *rport = target->rport;
271919081f31SDavid Dillow struct ib_device *dev = target->srp_host->srp_dev->dev;
2720aef9ec39SRoland Dreier struct srp_iu *iu;
2721aef9ec39SRoland Dreier struct srp_tsk_mgmt *tsk_mgmt;
27220a6fdbdeSBart Van Assche int res;
2723aef9ec39SRoland Dreier
2724c014c8cdSBart Van Assche if (!ch->connected || target->qp_in_error)
27253780d1f0SBart Van Assche return -1;
27263780d1f0SBart Van Assche
2727a95cadb9SBart Van Assche /*
2728509c07bcSBart Van Assche * Lock the rport mutex to avoid that srp_create_ch_ib() is
2729a95cadb9SBart Van Assche * invoked while a task management function is being sent.
2730a95cadb9SBart Van Assche */
2731a95cadb9SBart Van Assche mutex_lock(&rport->mutex);
2732509c07bcSBart Van Assche spin_lock_irq(&ch->lock);
2733509c07bcSBart Van Assche iu = __srp_get_tx_iu(ch, SRP_IU_TSK_MGMT);
2734509c07bcSBart Van Assche spin_unlock_irq(&ch->lock);
273576c75b25SBart Van Assche
2736a95cadb9SBart Van Assche if (!iu) {
2737a95cadb9SBart Van Assche mutex_unlock(&rport->mutex);
2738a95cadb9SBart Van Assche
273976c75b25SBart Van Assche return -1;
2740a95cadb9SBart Van Assche }
2741aef9ec39SRoland Dreier
2742882981f4SBart Van Assche iu->num_sge = 1;
2743882981f4SBart Van Assche
274419081f31SDavid Dillow ib_dma_sync_single_for_cpu(dev, iu->dma, sizeof *tsk_mgmt,
274519081f31SDavid Dillow DMA_TO_DEVICE);
2746aef9ec39SRoland Dreier tsk_mgmt = iu->buf;
2747aef9ec39SRoland Dreier memset(tsk_mgmt, 0, sizeof *tsk_mgmt);
2748aef9ec39SRoland Dreier
2749aef9ec39SRoland Dreier tsk_mgmt->opcode = SRP_TSK_MGMT;
2750985aa495SBart Van Assche int_to_scsilun(lun, &tsk_mgmt->lun);
2751aef9ec39SRoland Dreier tsk_mgmt->tsk_mgmt_func = func;
2752f8b6e31eSDavid Dillow tsk_mgmt->task_tag = req_tag;
2753aef9ec39SRoland Dreier
27540a6fdbdeSBart Van Assche spin_lock_irq(&ch->lock);
27550a6fdbdeSBart Van Assche ch->tsk_mgmt_tag = (ch->tsk_mgmt_tag + 1) | SRP_TAG_TSK_MGMT;
27560a6fdbdeSBart Van Assche tsk_mgmt->tag = ch->tsk_mgmt_tag;
27570a6fdbdeSBart Van Assche spin_unlock_irq(&ch->lock);
27580a6fdbdeSBart Van Assche
27590a6fdbdeSBart Van Assche init_completion(&ch->tsk_mgmt_done);
27600a6fdbdeSBart Van Assche
276119081f31SDavid Dillow ib_dma_sync_single_for_device(dev, iu->dma, sizeof *tsk_mgmt,
276219081f31SDavid Dillow DMA_TO_DEVICE);
2763509c07bcSBart Van Assche if (srp_post_send(ch, iu, sizeof(*tsk_mgmt))) {
2764509c07bcSBart Van Assche srp_put_tx_iu(ch, iu, SRP_IU_TSK_MGMT);
2765a95cadb9SBart Van Assche mutex_unlock(&rport->mutex);
2766a95cadb9SBart Van Assche
276776c75b25SBart Van Assche return -1;
276876c75b25SBart Van Assche }
27690a6fdbdeSBart Van Assche res = wait_for_completion_timeout(&ch->tsk_mgmt_done,
27700a6fdbdeSBart Van Assche msecs_to_jiffies(SRP_ABORT_TIMEOUT_MS));
27710a6fdbdeSBart Van Assche if (res > 0 && status)
27720a6fdbdeSBart Van Assche *status = ch->tsk_mgmt_status;
2773a95cadb9SBart Van Assche mutex_unlock(&rport->mutex);
2774d945e1dfSRoland Dreier
27750a6fdbdeSBart Van Assche WARN_ON_ONCE(res < 0);
2776aef9ec39SRoland Dreier
27770a6fdbdeSBart Van Assche return res > 0 ? 0 : -1;
2778d945e1dfSRoland Dreier }
2779d945e1dfSRoland Dreier
srp_abort(struct scsi_cmnd * scmnd)2780aef9ec39SRoland Dreier static int srp_abort(struct scsi_cmnd *scmnd)
2781aef9ec39SRoland Dreier {
2782d945e1dfSRoland Dreier struct srp_target_port *target = host_to_target(scmnd->device->host);
27836dbe4a8dSBart Van Assche struct srp_request *req = scsi_cmd_priv(scmnd);
278477f2c1a4SBart Van Assche u32 tag;
2785d92c0da7SBart Van Assche u16 ch_idx;
2786509c07bcSBart Van Assche struct srp_rdma_ch *ch;
2787d945e1dfSRoland Dreier
27887aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n");
2789aef9ec39SRoland Dreier
27909c5274eeSBart Van Assche tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmnd));
2791d92c0da7SBart Van Assche ch_idx = blk_mq_unique_tag_to_hwq(tag);
2792d92c0da7SBart Van Assche if (WARN_ON_ONCE(ch_idx >= target->ch_count))
2793d92c0da7SBart Van Assche return SUCCESS;
2794d92c0da7SBart Van Assche ch = &target->ch[ch_idx];
2795d92c0da7SBart Van Assche if (!srp_claim_req(ch, req, NULL, scmnd))
2796d92c0da7SBart Van Assche return SUCCESS;
2797d92c0da7SBart Van Assche shost_printk(KERN_ERR, target->scsi_host,
2798d92c0da7SBart Van Assche "Sending SRP abort for tag %#x\n", tag);
279977f2c1a4SBart Van Assche if (srp_send_tsk_mgmt(ch, tag, scmnd->device->lun,
2800*e193b795SBart Van Assche SRP_TSK_ABORT_TASK, NULL) == 0) {
2801509c07bcSBart Van Assche srp_free_req(ch, req, scmnd, 0);
2802*e193b795SBart Van Assche return SUCCESS;
2803e68088e7SBart Van Assche }
2804*e193b795SBart Van Assche if (target->rport->state == SRP_RPORT_LOST)
2805*e193b795SBart Van Assche return FAST_IO_FAIL;
2806d945e1dfSRoland Dreier
2807*e193b795SBart Van Assche return FAILED;
2808aef9ec39SRoland Dreier }
2809aef9ec39SRoland Dreier
srp_reset_device(struct scsi_cmnd * scmnd)2810aef9ec39SRoland Dreier static int srp_reset_device(struct scsi_cmnd *scmnd)
2811aef9ec39SRoland Dreier {
2812d945e1dfSRoland Dreier struct srp_target_port *target = host_to_target(scmnd->device->host);
2813d92c0da7SBart Van Assche struct srp_rdma_ch *ch;
28140a6fdbdeSBart Van Assche u8 status;
2815d945e1dfSRoland Dreier
28167aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, "SRP reset_device called\n");
2817aef9ec39SRoland Dreier
2818d92c0da7SBart Van Assche ch = &target->ch[0];
2819509c07bcSBart Van Assche if (srp_send_tsk_mgmt(ch, SRP_TAG_NO_REQ, scmnd->device->lun,
28200a6fdbdeSBart Van Assche SRP_TSK_LUN_RESET, &status))
2821d945e1dfSRoland Dreier return FAILED;
28220a6fdbdeSBart Van Assche if (status)
2823d945e1dfSRoland Dreier return FAILED;
2824d945e1dfSRoland Dreier
2825d945e1dfSRoland Dreier return SUCCESS;
2826aef9ec39SRoland Dreier }
2827aef9ec39SRoland Dreier
srp_reset_host(struct scsi_cmnd * scmnd)2828aef9ec39SRoland Dreier static int srp_reset_host(struct scsi_cmnd *scmnd)
2829aef9ec39SRoland Dreier {
2830aef9ec39SRoland Dreier struct srp_target_port *target = host_to_target(scmnd->device->host);
2831aef9ec39SRoland Dreier
28327aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX "SRP reset_host called\n");
2833aef9ec39SRoland Dreier
2834ed9b2264SBart Van Assche return srp_reconnect_rport(target->rport) == 0 ? SUCCESS : FAILED;
2835aef9ec39SRoland Dreier }
2836aef9ec39SRoland Dreier
srp_target_alloc(struct scsi_target * starget)2837b0780ee5SBart Van Assche static int srp_target_alloc(struct scsi_target *starget)
2838b0780ee5SBart Van Assche {
2839b0780ee5SBart Van Assche struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
2840b0780ee5SBart Van Assche struct srp_target_port *target = host_to_target(shost);
2841b0780ee5SBart Van Assche
2842b0780ee5SBart Van Assche if (target->target_can_queue)
2843b0780ee5SBart Van Assche starget->can_queue = target->target_can_queue;
2844b0780ee5SBart Van Assche return 0;
2845b0780ee5SBart Van Assche }
2846b0780ee5SBart Van Assche
srp_slave_configure(struct scsi_device * sdev)2847c9b03c1aSBart Van Assche static int srp_slave_configure(struct scsi_device *sdev)
2848c9b03c1aSBart Van Assche {
2849c9b03c1aSBart Van Assche struct Scsi_Host *shost = sdev->host;
2850c9b03c1aSBart Van Assche struct srp_target_port *target = host_to_target(shost);
2851c9b03c1aSBart Van Assche struct request_queue *q = sdev->request_queue;
2852c9b03c1aSBart Van Assche unsigned long timeout;
2853c9b03c1aSBart Van Assche
2854c9b03c1aSBart Van Assche if (sdev->type == TYPE_DISK) {
2855c9b03c1aSBart Van Assche timeout = max_t(unsigned, 30 * HZ, target->rq_tmo_jiffies);
2856c9b03c1aSBart Van Assche blk_queue_rq_timeout(q, timeout);
2857c9b03c1aSBart Van Assche }
2858c9b03c1aSBart Van Assche
2859c9b03c1aSBart Van Assche return 0;
2860c9b03c1aSBart Van Assche }
2861c9b03c1aSBart Van Assche
id_ext_show(struct device * dev,struct device_attribute * attr,char * buf)286233e82346SYueHaibing static ssize_t id_ext_show(struct device *dev, struct device_attribute *attr,
2863ee959b00STony Jones char *buf)
28646ecb0c84SRoland Dreier {
2865ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev));
28666ecb0c84SRoland Dreier
28671c7fd726SJoe Perches return sysfs_emit(buf, "0x%016llx\n", be64_to_cpu(target->id_ext));
28686ecb0c84SRoland Dreier }
28696ecb0c84SRoland Dreier
287033e82346SYueHaibing static DEVICE_ATTR_RO(id_ext);
287133e82346SYueHaibing
ioc_guid_show(struct device * dev,struct device_attribute * attr,char * buf)287233e82346SYueHaibing static ssize_t ioc_guid_show(struct device *dev, struct device_attribute *attr,
2873ee959b00STony Jones char *buf)
28746ecb0c84SRoland Dreier {
2875ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev));
28766ecb0c84SRoland Dreier
28771c7fd726SJoe Perches return sysfs_emit(buf, "0x%016llx\n", be64_to_cpu(target->ioc_guid));
28786ecb0c84SRoland Dreier }
28796ecb0c84SRoland Dreier
288033e82346SYueHaibing static DEVICE_ATTR_RO(ioc_guid);
288133e82346SYueHaibing
service_id_show(struct device * dev,struct device_attribute * attr,char * buf)288233e82346SYueHaibing static ssize_t service_id_show(struct device *dev,
2883ee959b00STony Jones struct device_attribute *attr, char *buf)
28846ecb0c84SRoland Dreier {
2885ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev));
28866ecb0c84SRoland Dreier
288719f31343SBart Van Assche if (target->using_rdma_cm)
288819f31343SBart Van Assche return -ENOENT;
28891c7fd726SJoe Perches return sysfs_emit(buf, "0x%016llx\n",
289019f31343SBart Van Assche be64_to_cpu(target->ib_cm.service_id));
28916ecb0c84SRoland Dreier }
28926ecb0c84SRoland Dreier
289333e82346SYueHaibing static DEVICE_ATTR_RO(service_id);
289433e82346SYueHaibing
pkey_show(struct device * dev,struct device_attribute * attr,char * buf)289533e82346SYueHaibing static ssize_t pkey_show(struct device *dev, struct device_attribute *attr,
2896ee959b00STony Jones char *buf)
28976ecb0c84SRoland Dreier {
2898ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev));
28996ecb0c84SRoland Dreier
290019f31343SBart Van Assche if (target->using_rdma_cm)
290119f31343SBart Van Assche return -ENOENT;
290245808361SJoe Perches
29031c7fd726SJoe Perches return sysfs_emit(buf, "0x%04x\n", be16_to_cpu(target->ib_cm.pkey));
29046ecb0c84SRoland Dreier }
29056ecb0c84SRoland Dreier
290633e82346SYueHaibing static DEVICE_ATTR_RO(pkey);
290733e82346SYueHaibing
sgid_show(struct device * dev,struct device_attribute * attr,char * buf)290833e82346SYueHaibing static ssize_t sgid_show(struct device *dev, struct device_attribute *attr,
2909848b3082SBart Van Assche char *buf)
2910848b3082SBart Van Assche {
2911848b3082SBart Van Assche struct srp_target_port *target = host_to_target(class_to_shost(dev));
2912848b3082SBart Van Assche
29131c7fd726SJoe Perches return sysfs_emit(buf, "%pI6\n", target->sgid.raw);
2914848b3082SBart Van Assche }
2915848b3082SBart Van Assche
291633e82346SYueHaibing static DEVICE_ATTR_RO(sgid);
291733e82346SYueHaibing
dgid_show(struct device * dev,struct device_attribute * attr,char * buf)291833e82346SYueHaibing static ssize_t dgid_show(struct device *dev, struct device_attribute *attr,
2919ee959b00STony Jones char *buf)
29206ecb0c84SRoland Dreier {
2921ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev));
2922d92c0da7SBart Van Assche struct srp_rdma_ch *ch = &target->ch[0];
29236ecb0c84SRoland Dreier
292419f31343SBart Van Assche if (target->using_rdma_cm)
292519f31343SBart Van Assche return -ENOENT;
292645808361SJoe Perches
29271c7fd726SJoe Perches return sysfs_emit(buf, "%pI6\n", ch->ib_cm.path.dgid.raw);
29286ecb0c84SRoland Dreier }
29296ecb0c84SRoland Dreier
293033e82346SYueHaibing static DEVICE_ATTR_RO(dgid);
293133e82346SYueHaibing
orig_dgid_show(struct device * dev,struct device_attribute * attr,char * buf)293233e82346SYueHaibing static ssize_t orig_dgid_show(struct device *dev, struct device_attribute *attr,
293333e82346SYueHaibing char *buf)
29343633b3d0SIshai Rabinovitz {
2935ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev));
29363633b3d0SIshai Rabinovitz
293719f31343SBart Van Assche if (target->using_rdma_cm)
293819f31343SBart Van Assche return -ENOENT;
293945808361SJoe Perches
29401c7fd726SJoe Perches return sysfs_emit(buf, "%pI6\n", target->ib_cm.orig_dgid.raw);
29413633b3d0SIshai Rabinovitz }
29423633b3d0SIshai Rabinovitz
294333e82346SYueHaibing static DEVICE_ATTR_RO(orig_dgid);
294433e82346SYueHaibing
req_lim_show(struct device * dev,struct device_attribute * attr,char * buf)294533e82346SYueHaibing static ssize_t req_lim_show(struct device *dev, struct device_attribute *attr,
294633e82346SYueHaibing char *buf)
294789de7486SBart Van Assche {
294889de7486SBart Van Assche struct srp_target_port *target = host_to_target(class_to_shost(dev));
2949d92c0da7SBart Van Assche struct srp_rdma_ch *ch;
2950d92c0da7SBart Van Assche int i, req_lim = INT_MAX;
295189de7486SBart Van Assche
2952d92c0da7SBart Van Assche for (i = 0; i < target->ch_count; i++) {
2953d92c0da7SBart Van Assche ch = &target->ch[i];
2954d92c0da7SBart Van Assche req_lim = min(req_lim, ch->req_lim);
2955d92c0da7SBart Van Assche }
295645808361SJoe Perches
29571c7fd726SJoe Perches return sysfs_emit(buf, "%d\n", req_lim);
295889de7486SBart Van Assche }
295989de7486SBart Van Assche
296033e82346SYueHaibing static DEVICE_ATTR_RO(req_lim);
296133e82346SYueHaibing
zero_req_lim_show(struct device * dev,struct device_attribute * attr,char * buf)296233e82346SYueHaibing static ssize_t zero_req_lim_show(struct device *dev,
2963ee959b00STony Jones struct device_attribute *attr, char *buf)
29646bfa24faSRoland Dreier {
2965ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev));
29666bfa24faSRoland Dreier
29671c7fd726SJoe Perches return sysfs_emit(buf, "%d\n", target->zero_req_lim);
29686bfa24faSRoland Dreier }
29696bfa24faSRoland Dreier
297033e82346SYueHaibing static DEVICE_ATTR_RO(zero_req_lim);
297133e82346SYueHaibing
local_ib_port_show(struct device * dev,struct device_attribute * attr,char * buf)297233e82346SYueHaibing static ssize_t local_ib_port_show(struct device *dev,
2973ee959b00STony Jones struct device_attribute *attr, char *buf)
2974ded7f1a1SIshai Rabinovitz {
2975ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev));
2976ded7f1a1SIshai Rabinovitz
2977b05398afSMikhael Goikhman return sysfs_emit(buf, "%u\n", target->srp_host->port);
2978ded7f1a1SIshai Rabinovitz }
2979ded7f1a1SIshai Rabinovitz
298033e82346SYueHaibing static DEVICE_ATTR_RO(local_ib_port);
298133e82346SYueHaibing
local_ib_device_show(struct device * dev,struct device_attribute * attr,char * buf)298233e82346SYueHaibing static ssize_t local_ib_device_show(struct device *dev,
2983ee959b00STony Jones struct device_attribute *attr, char *buf)
2984ded7f1a1SIshai Rabinovitz {
2985ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev));
2986ded7f1a1SIshai Rabinovitz
29871c7fd726SJoe Perches return sysfs_emit(buf, "%s\n",
29886c854111SJason Gunthorpe dev_name(&target->srp_host->srp_dev->dev->dev));
2989ded7f1a1SIshai Rabinovitz }
2990ded7f1a1SIshai Rabinovitz
299133e82346SYueHaibing static DEVICE_ATTR_RO(local_ib_device);
299233e82346SYueHaibing
ch_count_show(struct device * dev,struct device_attribute * attr,char * buf)299333e82346SYueHaibing static ssize_t ch_count_show(struct device *dev, struct device_attribute *attr,
2994d92c0da7SBart Van Assche char *buf)
2995d92c0da7SBart Van Assche {
2996d92c0da7SBart Van Assche struct srp_target_port *target = host_to_target(class_to_shost(dev));
2997d92c0da7SBart Van Assche
29981c7fd726SJoe Perches return sysfs_emit(buf, "%d\n", target->ch_count);
2999d92c0da7SBart Van Assche }
3000d92c0da7SBart Van Assche
300133e82346SYueHaibing static DEVICE_ATTR_RO(ch_count);
300233e82346SYueHaibing
comp_vector_show(struct device * dev,struct device_attribute * attr,char * buf)300333e82346SYueHaibing static ssize_t comp_vector_show(struct device *dev,
30044b5e5f41SBart Van Assche struct device_attribute *attr, char *buf)
30054b5e5f41SBart Van Assche {
30064b5e5f41SBart Van Assche struct srp_target_port *target = host_to_target(class_to_shost(dev));
30074b5e5f41SBart Van Assche
30081c7fd726SJoe Perches return sysfs_emit(buf, "%d\n", target->comp_vector);
30094b5e5f41SBart Van Assche }
30104b5e5f41SBart Van Assche
301133e82346SYueHaibing static DEVICE_ATTR_RO(comp_vector);
301233e82346SYueHaibing
tl_retry_count_show(struct device * dev,struct device_attribute * attr,char * buf)301333e82346SYueHaibing static ssize_t tl_retry_count_show(struct device *dev,
30147bb312e4SVu Pham struct device_attribute *attr, char *buf)
30157bb312e4SVu Pham {
30167bb312e4SVu Pham struct srp_target_port *target = host_to_target(class_to_shost(dev));
30177bb312e4SVu Pham
30181c7fd726SJoe Perches return sysfs_emit(buf, "%d\n", target->tl_retry_count);
30197bb312e4SVu Pham }
30207bb312e4SVu Pham
302133e82346SYueHaibing static DEVICE_ATTR_RO(tl_retry_count);
302233e82346SYueHaibing
cmd_sg_entries_show(struct device * dev,struct device_attribute * attr,char * buf)302333e82346SYueHaibing static ssize_t cmd_sg_entries_show(struct device *dev,
302449248644SDavid Dillow struct device_attribute *attr, char *buf)
302549248644SDavid Dillow {
302649248644SDavid Dillow struct srp_target_port *target = host_to_target(class_to_shost(dev));
302749248644SDavid Dillow
30281c7fd726SJoe Perches return sysfs_emit(buf, "%u\n", target->cmd_sg_cnt);
302949248644SDavid Dillow }
303049248644SDavid Dillow
303133e82346SYueHaibing static DEVICE_ATTR_RO(cmd_sg_entries);
303233e82346SYueHaibing
allow_ext_sg_show(struct device * dev,struct device_attribute * attr,char * buf)303333e82346SYueHaibing static ssize_t allow_ext_sg_show(struct device *dev,
3034c07d424dSDavid Dillow struct device_attribute *attr, char *buf)
3035c07d424dSDavid Dillow {
3036c07d424dSDavid Dillow struct srp_target_port *target = host_to_target(class_to_shost(dev));
3037c07d424dSDavid Dillow
30381c7fd726SJoe Perches return sysfs_emit(buf, "%s\n", target->allow_ext_sg ? "true" : "false");
3039c07d424dSDavid Dillow }
3040c07d424dSDavid Dillow
304133e82346SYueHaibing static DEVICE_ATTR_RO(allow_ext_sg);
30426ecb0c84SRoland Dreier
3043a3cf94c9SBart Van Assche static struct attribute *srp_host_attrs[] = {
3044a3cf94c9SBart Van Assche &dev_attr_id_ext.attr,
3045a3cf94c9SBart Van Assche &dev_attr_ioc_guid.attr,
3046a3cf94c9SBart Van Assche &dev_attr_service_id.attr,
3047a3cf94c9SBart Van Assche &dev_attr_pkey.attr,
3048a3cf94c9SBart Van Assche &dev_attr_sgid.attr,
3049a3cf94c9SBart Van Assche &dev_attr_dgid.attr,
3050a3cf94c9SBart Van Assche &dev_attr_orig_dgid.attr,
3051a3cf94c9SBart Van Assche &dev_attr_req_lim.attr,
3052a3cf94c9SBart Van Assche &dev_attr_zero_req_lim.attr,
3053a3cf94c9SBart Van Assche &dev_attr_local_ib_port.attr,
3054a3cf94c9SBart Van Assche &dev_attr_local_ib_device.attr,
3055a3cf94c9SBart Van Assche &dev_attr_ch_count.attr,
3056a3cf94c9SBart Van Assche &dev_attr_comp_vector.attr,
3057a3cf94c9SBart Van Assche &dev_attr_tl_retry_count.attr,
3058a3cf94c9SBart Van Assche &dev_attr_cmd_sg_entries.attr,
3059a3cf94c9SBart Van Assche &dev_attr_allow_ext_sg.attr,
30606ecb0c84SRoland Dreier NULL
30616ecb0c84SRoland Dreier };
30626ecb0c84SRoland Dreier
3063a3cf94c9SBart Van Assche ATTRIBUTE_GROUPS(srp_host);
3064a3cf94c9SBart Van Assche
30654281af9dSBart Van Assche static const struct scsi_host_template srp_template = {
3066aef9ec39SRoland Dreier .module = THIS_MODULE,
3067b7f008fdSRoland Dreier .name = "InfiniBand SRP initiator",
3068b7f008fdSRoland Dreier .proc_name = DRV_NAME,
3069b0780ee5SBart Van Assche .target_alloc = srp_target_alloc,
3070c9b03c1aSBart Van Assche .slave_configure = srp_slave_configure,
3071aef9ec39SRoland Dreier .info = srp_target_info,
3072ad215aaeSBart Van Assche .init_cmd_priv = srp_init_cmd_priv,
3073ad215aaeSBart Van Assche .exit_cmd_priv = srp_exit_cmd_priv,
3074aef9ec39SRoland Dreier .queuecommand = srp_queuecommand,
307571444b97SJack Wang .change_queue_depth = srp_change_queue_depth,
3076b6a05c82SChristoph Hellwig .eh_timed_out = srp_timed_out,
3077aef9ec39SRoland Dreier .eh_abort_handler = srp_abort,
3078aef9ec39SRoland Dreier .eh_device_reset_handler = srp_reset_device,
3079aef9ec39SRoland Dreier .eh_host_reset_handler = srp_reset_host,
30802742c1daSBart Van Assche .skip_settle_delay = true,
308149248644SDavid Dillow .sg_tablesize = SRP_DEF_SG_TABLESIZE,
30824d73f95fSBart Van Assche .can_queue = SRP_DEFAULT_CMD_SQ_SIZE,
3083aef9ec39SRoland Dreier .this_id = -1,
30844d73f95fSBart Van Assche .cmd_per_lun = SRP_DEFAULT_CMD_SQ_SIZE,
3085a3cf94c9SBart Van Assche .shost_groups = srp_host_groups,
3086c40ecc12SChristoph Hellwig .track_queue_depth = 1,
3087ad215aaeSBart Van Assche .cmd_size = sizeof(struct srp_request),
3088aef9ec39SRoland Dreier };
3089aef9ec39SRoland Dreier
srp_sdev_count(struct Scsi_Host * host)309034aa654eSBart Van Assche static int srp_sdev_count(struct Scsi_Host *host)
309134aa654eSBart Van Assche {
309234aa654eSBart Van Assche struct scsi_device *sdev;
309334aa654eSBart Van Assche int c = 0;
309434aa654eSBart Van Assche
309534aa654eSBart Van Assche shost_for_each_device(sdev, host)
309634aa654eSBart Van Assche c++;
309734aa654eSBart Van Assche
309834aa654eSBart Van Assche return c;
309934aa654eSBart Van Assche }
310034aa654eSBart Van Assche
3101bc44bd1dSBart Van Assche /*
3102bc44bd1dSBart Van Assche * Return values:
3103bc44bd1dSBart Van Assche * < 0 upon failure. Caller is responsible for SRP target port cleanup.
3104bc44bd1dSBart Van Assche * 0 and target->state == SRP_TARGET_REMOVED if asynchronous target port
3105bc44bd1dSBart Van Assche * removal has been scheduled.
3106bc44bd1dSBart Van Assche * 0 and target->state != SRP_TARGET_REMOVED upon success.
3107bc44bd1dSBart Van Assche */
srp_add_target(struct srp_host * host,struct srp_target_port * target)3108aef9ec39SRoland Dreier static int srp_add_target(struct srp_host *host, struct srp_target_port *target)
3109aef9ec39SRoland Dreier {
31103236822bSFUJITA Tomonori struct srp_rport_identifiers ids;
31113236822bSFUJITA Tomonori struct srp_rport *rport;
31123236822bSFUJITA Tomonori
311334aa654eSBart Van Assche target->state = SRP_TARGET_SCANNING;
3114aef9ec39SRoland Dreier sprintf(target->target_name, "SRP.T10:%016llX",
311545c37cadSBart Van Assche be64_to_cpu(target->id_ext));
3116aef9ec39SRoland Dreier
3117dee2b82aSBart Van Assche if (scsi_add_host(target->scsi_host, host->srp_dev->dev->dev.parent))
3118aef9ec39SRoland Dreier return -ENODEV;
3119aef9ec39SRoland Dreier
31203236822bSFUJITA Tomonori memcpy(ids.port_id, &target->id_ext, 8);
31213236822bSFUJITA Tomonori memcpy(ids.port_id + 8, &target->ioc_guid, 8);
3122aebd5e47SFUJITA Tomonori ids.roles = SRP_RPORT_ROLE_TARGET;
31233236822bSFUJITA Tomonori rport = srp_rport_add(target->scsi_host, &ids);
31243236822bSFUJITA Tomonori if (IS_ERR(rport)) {
31253236822bSFUJITA Tomonori scsi_remove_host(target->scsi_host);
31263236822bSFUJITA Tomonori return PTR_ERR(rport);
31273236822bSFUJITA Tomonori }
31283236822bSFUJITA Tomonori
3129dc1bdbd9SBart Van Assche rport->lld_data = target;
31309dd69a60SBart Van Assche target->rport = rport;
3131dc1bdbd9SBart Van Assche
3132b3589fd4SMatthew Wilcox spin_lock(&host->target_lock);
3133aef9ec39SRoland Dreier list_add_tail(&target->list, &host->target_list);
3134b3589fd4SMatthew Wilcox spin_unlock(&host->target_lock);
3135aef9ec39SRoland Dreier
3136aef9ec39SRoland Dreier scsi_scan_target(&target->scsi_host->shost_gendev,
31371d645088SHannes Reinecke 0, target->scsi_id, SCAN_WILD_CARD, SCSI_SCAN_INITIAL);
3138aef9ec39SRoland Dreier
3139c014c8cdSBart Van Assche if (srp_connected_ch(target) < target->ch_count ||
3140c014c8cdSBart Van Assche target->qp_in_error) {
314134aa654eSBart Van Assche shost_printk(KERN_INFO, target->scsi_host,
314234aa654eSBart Van Assche PFX "SCSI scan failed - removing SCSI host\n");
314334aa654eSBart Van Assche srp_queue_remove_work(target);
314434aa654eSBart Van Assche goto out;
314534aa654eSBart Van Assche }
314634aa654eSBart Van Assche
3147cf1acab7SBart Van Assche pr_debug("%s: SCSI scan succeeded - detected %d LUNs\n",
314834aa654eSBart Van Assche dev_name(&target->scsi_host->shost_gendev),
314934aa654eSBart Van Assche srp_sdev_count(target->scsi_host));
315034aa654eSBart Van Assche
315134aa654eSBart Van Assche spin_lock_irq(&target->lock);
315234aa654eSBart Van Assche if (target->state == SRP_TARGET_SCANNING)
315334aa654eSBart Van Assche target->state = SRP_TARGET_LIVE;
315434aa654eSBart Van Assche spin_unlock_irq(&target->lock);
315534aa654eSBart Van Assche
315634aa654eSBart Van Assche out:
3157aef9ec39SRoland Dreier return 0;
3158aef9ec39SRoland Dreier }
3159aef9ec39SRoland Dreier
srp_release_dev(struct device * dev)3160ee959b00STony Jones static void srp_release_dev(struct device *dev)
3161aef9ec39SRoland Dreier {
3162aef9ec39SRoland Dreier struct srp_host *host =
3163ee959b00STony Jones container_of(dev, struct srp_host, dev);
3164aef9ec39SRoland Dreier
31650766fcaaSBart Van Assche kfree(host);
3166aef9ec39SRoland Dreier }
3167aef9ec39SRoland Dreier
3168b8a9c18cSBart Van Assche static struct attribute *srp_class_attrs[];
3169b8a9c18cSBart Van Assche
3170b8a9c18cSBart Van Assche ATTRIBUTE_GROUPS(srp_class);
3171b8a9c18cSBart Van Assche
3172aef9ec39SRoland Dreier static struct class srp_class = {
3173aef9ec39SRoland Dreier .name = "infiniband_srp",
3174b8a9c18cSBart Van Assche .dev_groups = srp_class_groups,
3175ee959b00STony Jones .dev_release = srp_release_dev
3176aef9ec39SRoland Dreier };
3177aef9ec39SRoland Dreier
317896fc248aSBart Van Assche /**
317996fc248aSBart Van Assche * srp_conn_unique() - check whether the connection to a target is unique
3180af24663bSBart Van Assche * @host: SRP host.
3181af24663bSBart Van Assche * @target: SRP target port.
318296fc248aSBart Van Assche */
srp_conn_unique(struct srp_host * host,struct srp_target_port * target)318396fc248aSBart Van Assche static bool srp_conn_unique(struct srp_host *host,
318496fc248aSBart Van Assche struct srp_target_port *target)
318596fc248aSBart Van Assche {
318696fc248aSBart Van Assche struct srp_target_port *t;
318796fc248aSBart Van Assche bool ret = false;
318896fc248aSBart Van Assche
318996fc248aSBart Van Assche if (target->state == SRP_TARGET_REMOVED)
319096fc248aSBart Van Assche goto out;
319196fc248aSBart Van Assche
319296fc248aSBart Van Assche ret = true;
319396fc248aSBart Van Assche
319496fc248aSBart Van Assche spin_lock(&host->target_lock);
319596fc248aSBart Van Assche list_for_each_entry(t, &host->target_list, list) {
319696fc248aSBart Van Assche if (t != target &&
319796fc248aSBart Van Assche target->id_ext == t->id_ext &&
319896fc248aSBart Van Assche target->ioc_guid == t->ioc_guid &&
319996fc248aSBart Van Assche target->initiator_ext == t->initiator_ext) {
320096fc248aSBart Van Assche ret = false;
320196fc248aSBart Van Assche break;
320296fc248aSBart Van Assche }
320396fc248aSBart Van Assche }
320496fc248aSBart Van Assche spin_unlock(&host->target_lock);
320596fc248aSBart Van Assche
320696fc248aSBart Van Assche out:
320796fc248aSBart Van Assche return ret;
320896fc248aSBart Van Assche }
320996fc248aSBart Van Assche
3210aef9ec39SRoland Dreier /*
3211aef9ec39SRoland Dreier * Target ports are added by writing
3212aef9ec39SRoland Dreier *
3213aef9ec39SRoland Dreier * id_ext=<SRP ID ext>,ioc_guid=<SRP IOC GUID>,dgid=<dest GID>,
3214aef9ec39SRoland Dreier * pkey=<P_Key>,service_id=<service ID>
321519f31343SBart Van Assche * or
321619f31343SBart Van Assche * id_ext=<SRP ID ext>,ioc_guid=<SRP IOC GUID>,
321719f31343SBart Van Assche * [src=<IPv4 address>,]dest=<IPv4 address>:<port number>
3218aef9ec39SRoland Dreier *
3219aef9ec39SRoland Dreier * to the add_target sysfs attribute.
3220aef9ec39SRoland Dreier */
3221aef9ec39SRoland Dreier enum {
3222aef9ec39SRoland Dreier SRP_OPT_ERR = 0,
3223aef9ec39SRoland Dreier SRP_OPT_ID_EXT = 1 << 0,
3224aef9ec39SRoland Dreier SRP_OPT_IOC_GUID = 1 << 1,
3225aef9ec39SRoland Dreier SRP_OPT_DGID = 1 << 2,
3226aef9ec39SRoland Dreier SRP_OPT_PKEY = 1 << 3,
3227aef9ec39SRoland Dreier SRP_OPT_SERVICE_ID = 1 << 4,
3228aef9ec39SRoland Dreier SRP_OPT_MAX_SECT = 1 << 5,
322952fb2b50SVu Pham SRP_OPT_MAX_CMD_PER_LUN = 1 << 6,
32300c0450dbSRamachandra K SRP_OPT_IO_CLASS = 1 << 7,
323101cb9bcbSIshai Rabinovitz SRP_OPT_INITIATOR_EXT = 1 << 8,
323249248644SDavid Dillow SRP_OPT_CMD_SG_ENTRIES = 1 << 9,
3233c07d424dSDavid Dillow SRP_OPT_ALLOW_EXT_SG = 1 << 10,
3234c07d424dSDavid Dillow SRP_OPT_SG_TABLESIZE = 1 << 11,
32354b5e5f41SBart Van Assche SRP_OPT_COMP_VECTOR = 1 << 12,
32367bb312e4SVu Pham SRP_OPT_TL_RETRY_COUNT = 1 << 13,
32374d73f95fSBart Van Assche SRP_OPT_QUEUE_SIZE = 1 << 14,
323819f31343SBart Van Assche SRP_OPT_IP_SRC = 1 << 15,
323919f31343SBart Van Assche SRP_OPT_IP_DEST = 1 << 16,
3240b0780ee5SBart Van Assche SRP_OPT_TARGET_CAN_QUEUE= 1 << 17,
3241547ed331SHonggang Li SRP_OPT_MAX_IT_IU_SIZE = 1 << 18,
324287fee61cSBart Van Assche SRP_OPT_CH_COUNT = 1 << 19,
324319f31343SBart Van Assche };
324419f31343SBart Van Assche
324519f31343SBart Van Assche static unsigned int srp_opt_mandatory[] = {
324619f31343SBart Van Assche SRP_OPT_ID_EXT |
3247aef9ec39SRoland Dreier SRP_OPT_IOC_GUID |
3248aef9ec39SRoland Dreier SRP_OPT_DGID |
3249aef9ec39SRoland Dreier SRP_OPT_PKEY |
325019f31343SBart Van Assche SRP_OPT_SERVICE_ID,
325119f31343SBart Van Assche SRP_OPT_ID_EXT |
325219f31343SBart Van Assche SRP_OPT_IOC_GUID |
325319f31343SBart Van Assche SRP_OPT_IP_DEST,
3254aef9ec39SRoland Dreier };
3255aef9ec39SRoland Dreier
3256a447c093SSteven Whitehouse static const match_table_t srp_opt_tokens = {
3257aef9ec39SRoland Dreier { SRP_OPT_ID_EXT, "id_ext=%s" },
3258aef9ec39SRoland Dreier { SRP_OPT_IOC_GUID, "ioc_guid=%s" },
3259aef9ec39SRoland Dreier { SRP_OPT_DGID, "dgid=%s" },
3260aef9ec39SRoland Dreier { SRP_OPT_PKEY, "pkey=%x" },
3261aef9ec39SRoland Dreier { SRP_OPT_SERVICE_ID, "service_id=%s" },
3262aef9ec39SRoland Dreier { SRP_OPT_MAX_SECT, "max_sect=%d" },
326352fb2b50SVu Pham { SRP_OPT_MAX_CMD_PER_LUN, "max_cmd_per_lun=%d" },
3264b0780ee5SBart Van Assche { SRP_OPT_TARGET_CAN_QUEUE, "target_can_queue=%d" },
32650c0450dbSRamachandra K { SRP_OPT_IO_CLASS, "io_class=%x" },
326601cb9bcbSIshai Rabinovitz { SRP_OPT_INITIATOR_EXT, "initiator_ext=%s" },
326749248644SDavid Dillow { SRP_OPT_CMD_SG_ENTRIES, "cmd_sg_entries=%u" },
3268c07d424dSDavid Dillow { SRP_OPT_ALLOW_EXT_SG, "allow_ext_sg=%u" },
3269c07d424dSDavid Dillow { SRP_OPT_SG_TABLESIZE, "sg_tablesize=%u" },
32704b5e5f41SBart Van Assche { SRP_OPT_COMP_VECTOR, "comp_vector=%u" },
32717bb312e4SVu Pham { SRP_OPT_TL_RETRY_COUNT, "tl_retry_count=%u" },
32724d73f95fSBart Van Assche { SRP_OPT_QUEUE_SIZE, "queue_size=%d" },
327319f31343SBart Van Assche { SRP_OPT_IP_SRC, "src=%s" },
327419f31343SBart Van Assche { SRP_OPT_IP_DEST, "dest=%s" },
3275547ed331SHonggang Li { SRP_OPT_MAX_IT_IU_SIZE, "max_it_iu_size=%d" },
327687fee61cSBart Van Assche { SRP_OPT_CH_COUNT, "ch_count=%u", },
3277aef9ec39SRoland Dreier { SRP_OPT_ERR, NULL }
3278aef9ec39SRoland Dreier };
3279aef9ec39SRoland Dreier
3280c62adb7dSBart Van Assche /**
3281c62adb7dSBart Van Assche * srp_parse_in - parse an IP address and port number combination
3282e37df2d5SBart Van Assche * @net: [in] Network namespace.
3283e37df2d5SBart Van Assche * @sa: [out] Address family, IP address and port number.
3284e37df2d5SBart Van Assche * @addr_port_str: [in] IP address and port number.
3285bcef5b72SBart Van Assche * @has_port: [out] Whether or not @addr_port_str includes a port number.
3286c62adb7dSBart Van Assche *
3287c62adb7dSBart Van Assche * Parse the following address formats:
3288c62adb7dSBart Van Assche * - IPv4: <ip_address>:<port>, e.g. 1.2.3.4:5.
3289c62adb7dSBart Van Assche * - IPv6: \[<ipv6_address>\]:<port>, e.g. [1::2:3%4]:5.
3290c62adb7dSBart Van Assche */
srp_parse_in(struct net * net,struct sockaddr_storage * sa,const char * addr_port_str,bool * has_port)329119f31343SBart Van Assche static int srp_parse_in(struct net *net, struct sockaddr_storage *sa,
3292bcef5b72SBart Van Assche const char *addr_port_str, bool *has_port)
329319f31343SBart Van Assche {
3294c62adb7dSBart Van Assche char *addr_end, *addr = kstrdup(addr_port_str, GFP_KERNEL);
3295c62adb7dSBart Van Assche char *port_str;
329619f31343SBart Van Assche int ret;
329719f31343SBart Van Assche
329819f31343SBart Van Assche if (!addr)
329919f31343SBart Van Assche return -ENOMEM;
3300c62adb7dSBart Van Assche port_str = strrchr(addr, ':');
3301bcef5b72SBart Van Assche if (port_str && strchr(port_str, ']'))
3302bcef5b72SBart Van Assche port_str = NULL;
3303bcef5b72SBart Van Assche if (port_str)
3304c62adb7dSBart Van Assche *port_str++ = '\0';
3305bcef5b72SBart Van Assche if (has_port)
3306bcef5b72SBart Van Assche *has_port = port_str != NULL;
3307c62adb7dSBart Van Assche ret = inet_pton_with_scope(net, AF_INET, addr, port_str, sa);
3308c62adb7dSBart Van Assche if (ret && addr[0]) {
3309c62adb7dSBart Van Assche addr_end = addr + strlen(addr) - 1;
3310c62adb7dSBart Van Assche if (addr[0] == '[' && *addr_end == ']') {
3311c62adb7dSBart Van Assche *addr_end = '\0';
3312c62adb7dSBart Van Assche ret = inet_pton_with_scope(net, AF_INET6, addr + 1,
3313c62adb7dSBart Van Assche port_str, sa);
3314c62adb7dSBart Van Assche }
3315c62adb7dSBart Van Assche }
331619f31343SBart Van Assche kfree(addr);
3317c62adb7dSBart Van Assche pr_debug("%s -> %pISpfsc\n", addr_port_str, sa);
331819f31343SBart Van Assche return ret;
331919f31343SBart Van Assche }
332019f31343SBart Van Assche
srp_parse_options(struct net * net,const char * buf,struct srp_target_port * target)332119f31343SBart Van Assche static int srp_parse_options(struct net *net, const char *buf,
332219f31343SBart Van Assche struct srp_target_port *target)
3323aef9ec39SRoland Dreier {
3324aef9ec39SRoland Dreier char *options, *sep_opt;
3325aef9ec39SRoland Dreier char *p;
3326aef9ec39SRoland Dreier substring_t args[MAX_OPT_ARGS];
33272a174df0SBart Van Assche unsigned long long ull;
3328bcef5b72SBart Van Assche bool has_port;
3329aef9ec39SRoland Dreier int opt_mask = 0;
3330aef9ec39SRoland Dreier int token;
3331aef9ec39SRoland Dreier int ret = -EINVAL;
3332aef9ec39SRoland Dreier int i;
3333aef9ec39SRoland Dreier
3334aef9ec39SRoland Dreier options = kstrdup(buf, GFP_KERNEL);
3335aef9ec39SRoland Dreier if (!options)
3336aef9ec39SRoland Dreier return -ENOMEM;
3337aef9ec39SRoland Dreier
3338aef9ec39SRoland Dreier sep_opt = options;
33397dcf9c19SSagi Grimberg while ((p = strsep(&sep_opt, ",\n")) != NULL) {
3340aef9ec39SRoland Dreier if (!*p)
3341aef9ec39SRoland Dreier continue;
3342aef9ec39SRoland Dreier
3343aef9ec39SRoland Dreier token = match_token(p, srp_opt_tokens, args);
3344aef9ec39SRoland Dreier opt_mask |= token;
3345aef9ec39SRoland Dreier
3346aef9ec39SRoland Dreier switch (token) {
3347aef9ec39SRoland Dreier case SRP_OPT_ID_EXT:
3348aef9ec39SRoland Dreier p = match_strdup(args);
3349a20f3a6dSIshai Rabinovitz if (!p) {
3350a20f3a6dSIshai Rabinovitz ret = -ENOMEM;
3351a20f3a6dSIshai Rabinovitz goto out;
3352a20f3a6dSIshai Rabinovitz }
33532a174df0SBart Van Assche ret = kstrtoull(p, 16, &ull);
33542a174df0SBart Van Assche if (ret) {
33552a174df0SBart Van Assche pr_warn("invalid id_ext parameter '%s'\n", p);
33562a174df0SBart Van Assche kfree(p);
33572a174df0SBart Van Assche goto out;
33582a174df0SBart Van Assche }
33592a174df0SBart Van Assche target->id_ext = cpu_to_be64(ull);
3360aef9ec39SRoland Dreier kfree(p);
3361aef9ec39SRoland Dreier break;
3362aef9ec39SRoland Dreier
3363aef9ec39SRoland Dreier case SRP_OPT_IOC_GUID:
3364aef9ec39SRoland Dreier p = match_strdup(args);
3365a20f3a6dSIshai Rabinovitz if (!p) {
3366a20f3a6dSIshai Rabinovitz ret = -ENOMEM;
3367a20f3a6dSIshai Rabinovitz goto out;
3368a20f3a6dSIshai Rabinovitz }
33692a174df0SBart Van Assche ret = kstrtoull(p, 16, &ull);
33702a174df0SBart Van Assche if (ret) {
33712a174df0SBart Van Assche pr_warn("invalid ioc_guid parameter '%s'\n", p);
33722a174df0SBart Van Assche kfree(p);
33732a174df0SBart Van Assche goto out;
33742a174df0SBart Van Assche }
33752a174df0SBart Van Assche target->ioc_guid = cpu_to_be64(ull);
3376aef9ec39SRoland Dreier kfree(p);
3377aef9ec39SRoland Dreier break;
3378aef9ec39SRoland Dreier
3379aef9ec39SRoland Dreier case SRP_OPT_DGID:
3380aef9ec39SRoland Dreier p = match_strdup(args);
3381a20f3a6dSIshai Rabinovitz if (!p) {
3382a20f3a6dSIshai Rabinovitz ret = -ENOMEM;
3383a20f3a6dSIshai Rabinovitz goto out;
3384a20f3a6dSIshai Rabinovitz }
3385aef9ec39SRoland Dreier if (strlen(p) != 32) {
3386e0bda7d8SBart Van Assche pr_warn("bad dest GID parameter '%s'\n", p);
3387ce1823f0SRoland Dreier kfree(p);
3388aef9ec39SRoland Dreier goto out;
3389aef9ec39SRoland Dreier }
3390aef9ec39SRoland Dreier
339119f31343SBart Van Assche ret = hex2bin(target->ib_cm.orig_dgid.raw, p, 16);
3392747fe000SBart Van Assche kfree(p);
3393e711f968SAndy Shevchenko if (ret < 0)
3394747fe000SBart Van Assche goto out;
3395aef9ec39SRoland Dreier break;
3396aef9ec39SRoland Dreier
3397aef9ec39SRoland Dreier case SRP_OPT_PKEY:
3398ed461b30SWang Yufen ret = match_hex(args, &token);
3399ed461b30SWang Yufen if (ret) {
3400e0bda7d8SBart Van Assche pr_warn("bad P_Key parameter '%s'\n", p);
3401aef9ec39SRoland Dreier goto out;
3402aef9ec39SRoland Dreier }
340319f31343SBart Van Assche target->ib_cm.pkey = cpu_to_be16(token);
3404aef9ec39SRoland Dreier break;
3405aef9ec39SRoland Dreier
3406aef9ec39SRoland Dreier case SRP_OPT_SERVICE_ID:
3407aef9ec39SRoland Dreier p = match_strdup(args);
3408a20f3a6dSIshai Rabinovitz if (!p) {
3409a20f3a6dSIshai Rabinovitz ret = -ENOMEM;
3410a20f3a6dSIshai Rabinovitz goto out;
3411a20f3a6dSIshai Rabinovitz }
34122a174df0SBart Van Assche ret = kstrtoull(p, 16, &ull);
34132a174df0SBart Van Assche if (ret) {
34142a174df0SBart Van Assche pr_warn("bad service_id parameter '%s'\n", p);
34152a174df0SBart Van Assche kfree(p);
34162a174df0SBart Van Assche goto out;
34172a174df0SBart Van Assche }
341819f31343SBart Van Assche target->ib_cm.service_id = cpu_to_be64(ull);
341919f31343SBart Van Assche kfree(p);
342019f31343SBart Van Assche break;
342119f31343SBart Van Assche
342219f31343SBart Van Assche case SRP_OPT_IP_SRC:
342319f31343SBart Van Assche p = match_strdup(args);
342419f31343SBart Van Assche if (!p) {
342519f31343SBart Van Assche ret = -ENOMEM;
342619f31343SBart Van Assche goto out;
342719f31343SBart Van Assche }
3428bcef5b72SBart Van Assche ret = srp_parse_in(net, &target->rdma_cm.src.ss, p,
3429bcef5b72SBart Van Assche NULL);
343019f31343SBart Van Assche if (ret < 0) {
343119f31343SBart Van Assche pr_warn("bad source parameter '%s'\n", p);
343219f31343SBart Van Assche kfree(p);
343319f31343SBart Van Assche goto out;
343419f31343SBart Van Assche }
343519f31343SBart Van Assche target->rdma_cm.src_specified = true;
343619f31343SBart Van Assche kfree(p);
343719f31343SBart Van Assche break;
343819f31343SBart Van Assche
343919f31343SBart Van Assche case SRP_OPT_IP_DEST:
344019f31343SBart Van Assche p = match_strdup(args);
344119f31343SBart Van Assche if (!p) {
344219f31343SBart Van Assche ret = -ENOMEM;
344319f31343SBart Van Assche goto out;
344419f31343SBart Van Assche }
3445bcef5b72SBart Van Assche ret = srp_parse_in(net, &target->rdma_cm.dst.ss, p,
3446bcef5b72SBart Van Assche &has_port);
3447bcef5b72SBart Van Assche if (!has_port)
3448bcef5b72SBart Van Assche ret = -EINVAL;
344919f31343SBart Van Assche if (ret < 0) {
345019f31343SBart Van Assche pr_warn("bad dest parameter '%s'\n", p);
345119f31343SBart Van Assche kfree(p);
345219f31343SBart Van Assche goto out;
345319f31343SBart Van Assche }
345419f31343SBart Van Assche target->using_rdma_cm = true;
3455aef9ec39SRoland Dreier kfree(p);
3456aef9ec39SRoland Dreier break;
3457aef9ec39SRoland Dreier
3458aef9ec39SRoland Dreier case SRP_OPT_MAX_SECT:
3459ed461b30SWang Yufen ret = match_int(args, &token);
3460ed461b30SWang Yufen if (ret) {
3461e0bda7d8SBart Van Assche pr_warn("bad max sect parameter '%s'\n", p);
3462aef9ec39SRoland Dreier goto out;
3463aef9ec39SRoland Dreier }
3464aef9ec39SRoland Dreier target->scsi_host->max_sectors = token;
3465aef9ec39SRoland Dreier break;
3466aef9ec39SRoland Dreier
34674d73f95fSBart Van Assche case SRP_OPT_QUEUE_SIZE:
3468ed461b30SWang Yufen ret = match_int(args, &token);
3469ed461b30SWang Yufen if (ret) {
3470ed461b30SWang Yufen pr_warn("match_int() failed for queue_size parameter '%s', Error %d\n",
3471ed461b30SWang Yufen p, ret);
3472ed461b30SWang Yufen goto out;
3473ed461b30SWang Yufen }
3474ed461b30SWang Yufen if (token < 1) {
34754d73f95fSBart Van Assche pr_warn("bad queue_size parameter '%s'\n", p);
3476ed461b30SWang Yufen ret = -EINVAL;
34774d73f95fSBart Van Assche goto out;
34784d73f95fSBart Van Assche }
34794d73f95fSBart Van Assche target->scsi_host->can_queue = token;
34804d73f95fSBart Van Assche target->queue_size = token + SRP_RSP_SQ_SIZE +
34814d73f95fSBart Van Assche SRP_TSK_MGMT_SQ_SIZE;
34824d73f95fSBart Van Assche if (!(opt_mask & SRP_OPT_MAX_CMD_PER_LUN))
34834d73f95fSBart Van Assche target->scsi_host->cmd_per_lun = token;
34844d73f95fSBart Van Assche break;
34854d73f95fSBart Van Assche
348652fb2b50SVu Pham case SRP_OPT_MAX_CMD_PER_LUN:
3487ed461b30SWang Yufen ret = match_int(args, &token);
3488ed461b30SWang Yufen if (ret) {
3489ed461b30SWang Yufen pr_warn("match_int() failed for max cmd_per_lun parameter '%s', Error %d\n",
3490ed461b30SWang Yufen p, ret);
3491ed461b30SWang Yufen goto out;
3492ed461b30SWang Yufen }
3493ed461b30SWang Yufen if (token < 1) {
3494e0bda7d8SBart Van Assche pr_warn("bad max cmd_per_lun parameter '%s'\n",
3495e0bda7d8SBart Van Assche p);
3496ed461b30SWang Yufen ret = -EINVAL;
349752fb2b50SVu Pham goto out;
349852fb2b50SVu Pham }
34994d73f95fSBart Van Assche target->scsi_host->cmd_per_lun = token;
350052fb2b50SVu Pham break;
350152fb2b50SVu Pham
3502b0780ee5SBart Van Assche case SRP_OPT_TARGET_CAN_QUEUE:
3503ed461b30SWang Yufen ret = match_int(args, &token);
3504ed461b30SWang Yufen if (ret) {
3505ed461b30SWang Yufen pr_warn("match_int() failed for max target_can_queue parameter '%s', Error %d\n",
3506ed461b30SWang Yufen p, ret);
3507ed461b30SWang Yufen goto out;
3508ed461b30SWang Yufen }
3509ed461b30SWang Yufen if (token < 1) {
3510b0780ee5SBart Van Assche pr_warn("bad max target_can_queue parameter '%s'\n",
3511b0780ee5SBart Van Assche p);
3512ed461b30SWang Yufen ret = -EINVAL;
3513b0780ee5SBart Van Assche goto out;
3514b0780ee5SBart Van Assche }
3515b0780ee5SBart Van Assche target->target_can_queue = token;
3516b0780ee5SBart Van Assche break;
3517b0780ee5SBart Van Assche
35180c0450dbSRamachandra K case SRP_OPT_IO_CLASS:
3519ed461b30SWang Yufen ret = match_hex(args, &token);
3520ed461b30SWang Yufen if (ret) {
3521e0bda7d8SBart Van Assche pr_warn("bad IO class parameter '%s'\n", p);
35220c0450dbSRamachandra K goto out;
35230c0450dbSRamachandra K }
35240c0450dbSRamachandra K if (token != SRP_REV10_IB_IO_CLASS &&
35250c0450dbSRamachandra K token != SRP_REV16A_IB_IO_CLASS) {
3526e0bda7d8SBart Van Assche pr_warn("unknown IO class parameter value %x specified (use %x or %x).\n",
3527e0bda7d8SBart Van Assche token, SRP_REV10_IB_IO_CLASS,
3528e0bda7d8SBart Van Assche SRP_REV16A_IB_IO_CLASS);
3529ed461b30SWang Yufen ret = -EINVAL;
35300c0450dbSRamachandra K goto out;
35310c0450dbSRamachandra K }
35320c0450dbSRamachandra K target->io_class = token;
35330c0450dbSRamachandra K break;
35340c0450dbSRamachandra K
353501cb9bcbSIshai Rabinovitz case SRP_OPT_INITIATOR_EXT:
353601cb9bcbSIshai Rabinovitz p = match_strdup(args);
3537a20f3a6dSIshai Rabinovitz if (!p) {
3538a20f3a6dSIshai Rabinovitz ret = -ENOMEM;
3539a20f3a6dSIshai Rabinovitz goto out;
3540a20f3a6dSIshai Rabinovitz }
35412a174df0SBart Van Assche ret = kstrtoull(p, 16, &ull);
35422a174df0SBart Van Assche if (ret) {
35432a174df0SBart Van Assche pr_warn("bad initiator_ext value '%s'\n", p);
35442a174df0SBart Van Assche kfree(p);
35452a174df0SBart Van Assche goto out;
35462a174df0SBart Van Assche }
35472a174df0SBart Van Assche target->initiator_ext = cpu_to_be64(ull);
354801cb9bcbSIshai Rabinovitz kfree(p);
354901cb9bcbSIshai Rabinovitz break;
355001cb9bcbSIshai Rabinovitz
355149248644SDavid Dillow case SRP_OPT_CMD_SG_ENTRIES:
3552ed461b30SWang Yufen ret = match_int(args, &token);
3553ed461b30SWang Yufen if (ret) {
3554ed461b30SWang Yufen pr_warn("match_int() failed for max cmd_sg_entries parameter '%s', Error %d\n",
3555ed461b30SWang Yufen p, ret);
3556ed461b30SWang Yufen goto out;
3557ed461b30SWang Yufen }
3558ed461b30SWang Yufen if (token < 1 || token > 255) {
3559e0bda7d8SBart Van Assche pr_warn("bad max cmd_sg_entries parameter '%s'\n",
3560e0bda7d8SBart Van Assche p);
3561ed461b30SWang Yufen ret = -EINVAL;
356249248644SDavid Dillow goto out;
356349248644SDavid Dillow }
356449248644SDavid Dillow target->cmd_sg_cnt = token;
356549248644SDavid Dillow break;
356649248644SDavid Dillow
3567c07d424dSDavid Dillow case SRP_OPT_ALLOW_EXT_SG:
3568ed461b30SWang Yufen ret = match_int(args, &token);
3569ed461b30SWang Yufen if (ret) {
3570e0bda7d8SBart Van Assche pr_warn("bad allow_ext_sg parameter '%s'\n", p);
3571c07d424dSDavid Dillow goto out;
3572c07d424dSDavid Dillow }
3573c07d424dSDavid Dillow target->allow_ext_sg = !!token;
3574c07d424dSDavid Dillow break;
3575c07d424dSDavid Dillow
3576c07d424dSDavid Dillow case SRP_OPT_SG_TABLESIZE:
3577ed461b30SWang Yufen ret = match_int(args, &token);
3578ed461b30SWang Yufen if (ret) {
3579ed461b30SWang Yufen pr_warn("match_int() failed for max sg_tablesize parameter '%s', Error %d\n",
3580ed461b30SWang Yufen p, ret);
3581ed461b30SWang Yufen goto out;
3582ed461b30SWang Yufen }
3583ed461b30SWang Yufen if (token < 1 || token > SG_MAX_SEGMENTS) {
3584e0bda7d8SBart Van Assche pr_warn("bad max sg_tablesize parameter '%s'\n",
3585e0bda7d8SBart Van Assche p);
3586ed461b30SWang Yufen ret = -EINVAL;
3587c07d424dSDavid Dillow goto out;
3588c07d424dSDavid Dillow }
3589c07d424dSDavid Dillow target->sg_tablesize = token;
3590c07d424dSDavid Dillow break;
3591c07d424dSDavid Dillow
35924b5e5f41SBart Van Assche case SRP_OPT_COMP_VECTOR:
3593ed461b30SWang Yufen ret = match_int(args, &token);
3594ed461b30SWang Yufen if (ret) {
3595ed461b30SWang Yufen pr_warn("match_int() failed for comp_vector parameter '%s', Error %d\n",
3596ed461b30SWang Yufen p, ret);
3597ed461b30SWang Yufen goto out;
3598ed461b30SWang Yufen }
3599ed461b30SWang Yufen if (token < 0) {
36004b5e5f41SBart Van Assche pr_warn("bad comp_vector parameter '%s'\n", p);
3601ed461b30SWang Yufen ret = -EINVAL;
36024b5e5f41SBart Van Assche goto out;
36034b5e5f41SBart Van Assche }
36044b5e5f41SBart Van Assche target->comp_vector = token;
36054b5e5f41SBart Van Assche break;
36064b5e5f41SBart Van Assche
36077bb312e4SVu Pham case SRP_OPT_TL_RETRY_COUNT:
3608ed461b30SWang Yufen ret = match_int(args, &token);
3609ed461b30SWang Yufen if (ret) {
3610ed461b30SWang Yufen pr_warn("match_int() failed for tl_retry_count parameter '%s', Error %d\n",
3611ed461b30SWang Yufen p, ret);
3612ed461b30SWang Yufen goto out;
3613ed461b30SWang Yufen }
3614ed461b30SWang Yufen if (token < 2 || token > 7) {
36157bb312e4SVu Pham pr_warn("bad tl_retry_count parameter '%s' (must be a number between 2 and 7)\n",
36167bb312e4SVu Pham p);
3617ed461b30SWang Yufen ret = -EINVAL;
36187bb312e4SVu Pham goto out;
36197bb312e4SVu Pham }
36207bb312e4SVu Pham target->tl_retry_count = token;
36217bb312e4SVu Pham break;
36227bb312e4SVu Pham
3623547ed331SHonggang Li case SRP_OPT_MAX_IT_IU_SIZE:
3624ed461b30SWang Yufen ret = match_int(args, &token);
3625ed461b30SWang Yufen if (ret) {
3626ed461b30SWang Yufen pr_warn("match_int() failed for max it_iu_size parameter '%s', Error %d\n",
3627ed461b30SWang Yufen p, ret);
3628ed461b30SWang Yufen goto out;
3629ed461b30SWang Yufen }
3630ed461b30SWang Yufen if (token < 0) {
3631547ed331SHonggang Li pr_warn("bad maximum initiator to target IU size '%s'\n", p);
3632ed461b30SWang Yufen ret = -EINVAL;
3633547ed331SHonggang Li goto out;
3634547ed331SHonggang Li }
3635547ed331SHonggang Li target->max_it_iu_size = token;
3636547ed331SHonggang Li break;
3637547ed331SHonggang Li
363887fee61cSBart Van Assche case SRP_OPT_CH_COUNT:
3639ed461b30SWang Yufen ret = match_int(args, &token);
3640ed461b30SWang Yufen if (ret) {
3641ed461b30SWang Yufen pr_warn("match_int() failed for channel count parameter '%s', Error %d\n",
3642ed461b30SWang Yufen p, ret);
3643ed461b30SWang Yufen goto out;
3644ed461b30SWang Yufen }
3645ed461b30SWang Yufen if (token < 1) {
364687fee61cSBart Van Assche pr_warn("bad channel count %s\n", p);
3647ed461b30SWang Yufen ret = -EINVAL;
364887fee61cSBart Van Assche goto out;
364987fee61cSBart Van Assche }
365087fee61cSBart Van Assche target->ch_count = token;
365187fee61cSBart Van Assche break;
365287fee61cSBart Van Assche
3653aef9ec39SRoland Dreier default:
3654e0bda7d8SBart Van Assche pr_warn("unknown parameter or missing value '%s' in target creation request\n",
3655e0bda7d8SBart Van Assche p);
3656ed461b30SWang Yufen ret = -EINVAL;
3657aef9ec39SRoland Dreier goto out;
3658aef9ec39SRoland Dreier }
3659aef9ec39SRoland Dreier }
3660aef9ec39SRoland Dreier
366119f31343SBart Van Assche for (i = 0; i < ARRAY_SIZE(srp_opt_mandatory); i++) {
366219f31343SBart Van Assche if ((opt_mask & srp_opt_mandatory[i]) == srp_opt_mandatory[i]) {
3663aef9ec39SRoland Dreier ret = 0;
366419f31343SBart Van Assche break;
366519f31343SBart Van Assche }
366619f31343SBart Van Assche }
366719f31343SBart Van Assche if (ret)
366819f31343SBart Van Assche pr_warn("target creation request is missing one or more parameters\n");
3669aef9ec39SRoland Dreier
36704d73f95fSBart Van Assche if (target->scsi_host->cmd_per_lun > target->scsi_host->can_queue
36714d73f95fSBart Van Assche && (opt_mask & SRP_OPT_MAX_CMD_PER_LUN))
36724d73f95fSBart Van Assche pr_warn("cmd_per_lun = %d > queue_size = %d\n",
36734d73f95fSBart Van Assche target->scsi_host->cmd_per_lun,
36744d73f95fSBart Van Assche target->scsi_host->can_queue);
36754d73f95fSBart Van Assche
3676aef9ec39SRoland Dreier out:
3677aef9ec39SRoland Dreier kfree(options);
3678aef9ec39SRoland Dreier return ret;
3679aef9ec39SRoland Dreier }
3680aef9ec39SRoland Dreier
add_target_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)368133e82346SYueHaibing static ssize_t add_target_store(struct device *dev,
368233e82346SYueHaibing struct device_attribute *attr, const char *buf,
368333e82346SYueHaibing size_t count)
3684aef9ec39SRoland Dreier {
3685aef9ec39SRoland Dreier struct srp_host *host =
3686ee959b00STony Jones container_of(dev, struct srp_host, dev);
3687aef9ec39SRoland Dreier struct Scsi_Host *target_host;
3688aef9ec39SRoland Dreier struct srp_target_port *target;
3689509c07bcSBart Van Assche struct srp_rdma_ch *ch;
3690d1b4289eSBart Van Assche struct srp_device *srp_dev = host->srp_dev;
3691d1b4289eSBart Van Assche struct ib_device *ibdev = srp_dev->dev;
36922b5715fcSNicolas Morey-Chaisemartin int ret, i, ch_idx;
3693509c5f33SBart Van Assche unsigned int max_sectors_per_mr, mr_per_cmd = 0;
3694d92c0da7SBart Van Assche bool multich = false;
3695513d5647SBart Van Assche uint32_t max_iu_len;
3696aef9ec39SRoland Dreier
3697aef9ec39SRoland Dreier target_host = scsi_host_alloc(&srp_template,
3698aef9ec39SRoland Dreier sizeof (struct srp_target_port));
3699aef9ec39SRoland Dreier if (!target_host)
3700aef9ec39SRoland Dreier return -ENOMEM;
3701aef9ec39SRoland Dreier
37023236822bSFUJITA Tomonori target_host->transportt = ib_srp_transport_template;
3703fd1b6c4aSBart Van Assche target_host->max_channel = 0;
3704fd1b6c4aSBart Van Assche target_host->max_id = 1;
3705985aa495SBart Van Assche target_host->max_lun = -1LL;
37063c8edf0eSArne Redlich target_host->max_cmd_len = sizeof ((struct srp_cmd *) (void *) 0L)->cdb;
37070b5cb330SBart Van Assche target_host->max_segment_size = ib_dma_max_seg_size(ibdev);
37085f068992SRoland Dreier
3709e945c653SJason Gunthorpe if (!(ibdev->attrs.kernel_cap_flags & IBK_SG_GAPS_REG))
37108c175d31SChristoph Hellwig target_host->virt_boundary_mask = ~srp_dev->mr_page_mask;
37118c175d31SChristoph Hellwig
3712aef9ec39SRoland Dreier target = host_to_target(target_host);
3713aef9ec39SRoland Dreier
371419f31343SBart Van Assche target->net = kobj_ns_grab_current(KOBJ_NS_TYPE_NET);
37150c0450dbSRamachandra K target->io_class = SRP_REV16A_IB_IO_CLASS;
3716aef9ec39SRoland Dreier target->scsi_host = target_host;
3717aef9ec39SRoland Dreier target->srp_host = host;
3718e6bf5f48SJason Gunthorpe target->lkey = host->srp_dev->pd->local_dma_lkey;
3719cee687b6SBart Van Assche target->global_rkey = host->srp_dev->global_rkey;
372049248644SDavid Dillow target->cmd_sg_cnt = cmd_sg_entries;
3721c07d424dSDavid Dillow target->sg_tablesize = indirect_sg_entries ? : cmd_sg_entries;
3722c07d424dSDavid Dillow target->allow_ext_sg = allow_ext_sg;
37237bb312e4SVu Pham target->tl_retry_count = 7;
37244d73f95fSBart Van Assche target->queue_size = SRP_DEFAULT_QUEUE_SIZE;
3725aef9ec39SRoland Dreier
372634aa654eSBart Van Assche /*
372734aa654eSBart Van Assche * Avoid that the SCSI host can be removed by srp_remove_target()
372834aa654eSBart Van Assche * before this function returns.
372934aa654eSBart Van Assche */
373034aa654eSBart Van Assche scsi_host_get(target->scsi_host);
373134aa654eSBart Van Assche
37324fa354c9SBart Van Assche ret = mutex_lock_interruptible(&host->add_target_mutex);
37334fa354c9SBart Van Assche if (ret < 0)
37344fa354c9SBart Van Assche goto put;
37352d7091bcSBart Van Assche
373619f31343SBart Van Assche ret = srp_parse_options(target->net, buf, target);
3737aef9ec39SRoland Dreier if (ret)
3738fb49c8bbSBart Van Assche goto out;
3739aef9ec39SRoland Dreier
374096fc248aSBart Van Assche if (!srp_conn_unique(target->srp_host, target)) {
374119f31343SBart Van Assche if (target->using_rdma_cm) {
374219f31343SBart Van Assche shost_printk(KERN_INFO, target->scsi_host,
37437da09af9SBart Van Assche PFX "Already connected to target port with id_ext=%016llx;ioc_guid=%016llx;dest=%pIS\n",
374419f31343SBart Van Assche be64_to_cpu(target->id_ext),
374519f31343SBart Van Assche be64_to_cpu(target->ioc_guid),
37467da09af9SBart Van Assche &target->rdma_cm.dst);
374719f31343SBart Van Assche } else {
374896fc248aSBart Van Assche shost_printk(KERN_INFO, target->scsi_host,
374996fc248aSBart Van Assche PFX "Already connected to target port with id_ext=%016llx;ioc_guid=%016llx;initiator_ext=%016llx\n",
375096fc248aSBart Van Assche be64_to_cpu(target->id_ext),
375196fc248aSBart Van Assche be64_to_cpu(target->ioc_guid),
375296fc248aSBart Van Assche be64_to_cpu(target->initiator_ext));
375319f31343SBart Van Assche }
375496fc248aSBart Van Assche ret = -EEXIST;
3755fb49c8bbSBart Van Assche goto out;
375696fc248aSBart Van Assche }
375796fc248aSBart Van Assche
3758f273ad4fSMax Gurtovoy if (!srp_dev->has_fr && !target->allow_ext_sg &&
3759c07d424dSDavid Dillow target->cmd_sg_cnt < target->sg_tablesize) {
37605cfb1782SBart Van Assche pr_warn("No MR pool and no external indirect descriptors, limiting sg_tablesize to cmd_sg_cnt\n");
3761c07d424dSDavid Dillow target->sg_tablesize = target->cmd_sg_cnt;
3762c07d424dSDavid Dillow }
3763c07d424dSDavid Dillow
3764f273ad4fSMax Gurtovoy if (srp_dev->use_fast_reg) {
3765e945c653SJason Gunthorpe bool gaps_reg = ibdev->attrs.kernel_cap_flags &
3766e945c653SJason Gunthorpe IBK_SG_GAPS_REG;
3767fbd36818SSergey Gorenko
3768509c5f33SBart Van Assche max_sectors_per_mr = srp_dev->max_pages_per_mr <<
3769509c5f33SBart Van Assche (ilog2(srp_dev->mr_page_size) - 9);
3770fbd36818SSergey Gorenko if (!gaps_reg) {
3771fbd36818SSergey Gorenko /*
3772f273ad4fSMax Gurtovoy * FR can only map one HCA page per entry. If the start
3773f273ad4fSMax Gurtovoy * address is not aligned on a HCA page boundary two
3774f273ad4fSMax Gurtovoy * entries will be used for the head and the tail
3775f273ad4fSMax Gurtovoy * although these two entries combined contain at most
3776f273ad4fSMax Gurtovoy * one HCA page of data. Hence the "+ 1" in the
3777f273ad4fSMax Gurtovoy * calculation below.
3778fbd36818SSergey Gorenko *
3779fbd36818SSergey Gorenko * The indirect data buffer descriptor is contiguous
3780fbd36818SSergey Gorenko * so the memory for that buffer will only be
3781fbd36818SSergey Gorenko * registered if register_always is true. Hence add
3782fbd36818SSergey Gorenko * one to mr_per_cmd if register_always has been set.
3783fbd36818SSergey Gorenko */
3784509c5f33SBart Van Assche mr_per_cmd = register_always +
3785509c5f33SBart Van Assche (target->scsi_host->max_sectors + 1 +
3786509c5f33SBart Van Assche max_sectors_per_mr - 1) / max_sectors_per_mr;
3787fbd36818SSergey Gorenko } else {
3788fbd36818SSergey Gorenko mr_per_cmd = register_always +
3789fbd36818SSergey Gorenko (target->sg_tablesize +
3790fbd36818SSergey Gorenko srp_dev->max_pages_per_mr - 1) /
3791fbd36818SSergey Gorenko srp_dev->max_pages_per_mr;
3792fbd36818SSergey Gorenko }
3793509c5f33SBart Van Assche pr_debug("max_sectors = %u; max_pages_per_mr = %u; mr_page_size = %u; max_sectors_per_mr = %u; mr_per_cmd = %u\n",
3794fbd36818SSergey Gorenko target->scsi_host->max_sectors, srp_dev->max_pages_per_mr, srp_dev->mr_page_size,
3795509c5f33SBart Van Assche max_sectors_per_mr, mr_per_cmd);
3796509c5f33SBart Van Assche }
3797509c5f33SBart Van Assche
3798c07d424dSDavid Dillow target_host->sg_tablesize = target->sg_tablesize;
3799509c5f33SBart Van Assche target->mr_pool_size = target->scsi_host->can_queue * mr_per_cmd;
3800509c5f33SBart Van Assche target->mr_per_cmd = mr_per_cmd;
3801c07d424dSDavid Dillow target->indirect_size = target->sg_tablesize *
3802c07d424dSDavid Dillow sizeof (struct srp_direct_buf);
3803b2e872f4SHonggang Li max_iu_len = srp_max_it_iu_len(target->cmd_sg_cnt,
3804b2e872f4SHonggang Li srp_use_imm_data,
3805b2e872f4SHonggang Li target->max_it_iu_size);
380649248644SDavid Dillow
3807c1120f89SBart Van Assche INIT_WORK(&target->tl_err_work, srp_tl_err_work);
3808ef6c49d8SBart Van Assche INIT_WORK(&target->remove_work, srp_remove_work);
38098f26c9ffSDavid Dillow spin_lock_init(&target->lock);
38101dfce294SParav Pandit ret = rdma_query_gid(ibdev, host->port, 0, &target->sgid);
38112088ca66SSagi Grimberg if (ret)
3812fb49c8bbSBart Van Assche goto out;
3813d92c0da7SBart Van Assche
3814d92c0da7SBart Van Assche ret = -ENOMEM;
38152b5715fcSNicolas Morey-Chaisemartin if (target->ch_count == 0) {
381687fee61cSBart Van Assche target->ch_count =
3817d92c0da7SBart Van Assche min(ch_count ?:
38182b5715fcSNicolas Morey-Chaisemartin max(4 * num_online_nodes(),
3819d92c0da7SBart Van Assche ibdev->num_comp_vectors),
38202b5715fcSNicolas Morey-Chaisemartin num_online_cpus());
38212b5715fcSNicolas Morey-Chaisemartin }
38222b5715fcSNicolas Morey-Chaisemartin
3823d92c0da7SBart Van Assche target->ch = kcalloc(target->ch_count, sizeof(*target->ch),
3824d92c0da7SBart Van Assche GFP_KERNEL);
3825d92c0da7SBart Van Assche if (!target->ch)
3826fb49c8bbSBart Van Assche goto out;
3827d92c0da7SBart Van Assche
38282b5715fcSNicolas Morey-Chaisemartin for (ch_idx = 0; ch_idx < target->ch_count; ++ch_idx) {
38292b5715fcSNicolas Morey-Chaisemartin ch = &target->ch[ch_idx];
3830d92c0da7SBart Van Assche ch->target = target;
38312b5715fcSNicolas Morey-Chaisemartin ch->comp_vector = ch_idx % ibdev->num_comp_vectors;
3832d92c0da7SBart Van Assche spin_lock_init(&ch->lock);
3833d92c0da7SBart Van Assche INIT_LIST_HEAD(&ch->free_tx);
3834d92c0da7SBart Van Assche ret = srp_new_cm_id(ch);
3835d92c0da7SBart Van Assche if (ret)
3836d92c0da7SBart Van Assche goto err_disconnect;
3837aef9ec39SRoland Dreier
3838509c07bcSBart Van Assche ret = srp_create_ch_ib(ch);
3839aef9ec39SRoland Dreier if (ret)
3840d92c0da7SBart Van Assche goto err_disconnect;
3841aef9ec39SRoland Dreier
3842513d5647SBart Van Assche ret = srp_connect_ch(ch, max_iu_len, multich);
3843aef9ec39SRoland Dreier if (ret) {
384419f31343SBart Van Assche char dst[64];
384519f31343SBart Van Assche
384619f31343SBart Van Assche if (target->using_rdma_cm)
38477da09af9SBart Van Assche snprintf(dst, sizeof(dst), "%pIS",
38487da09af9SBart Van Assche &target->rdma_cm.dst);
384919f31343SBart Van Assche else
385019f31343SBart Van Assche snprintf(dst, sizeof(dst), "%pI6",
385119f31343SBart Van Assche target->ib_cm.orig_dgid.raw);
38527aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host,
385319f31343SBart Van Assche PFX "Connection %d/%d to %s failed\n",
38542b5715fcSNicolas Morey-Chaisemartin ch_idx,
385519f31343SBart Van Assche target->ch_count, dst);
38562b5715fcSNicolas Morey-Chaisemartin if (ch_idx == 0) {
3857b02c1536SBart Van Assche goto free_ch;
3858d92c0da7SBart Van Assche } else {
3859d92c0da7SBart Van Assche srp_free_ch_ib(target, ch);
3860d92c0da7SBart Van Assche target->ch_count = ch - target->ch;
3861c257ea6fSBart Van Assche goto connected;
3862aef9ec39SRoland Dreier }
3863d92c0da7SBart Van Assche }
3864d92c0da7SBart Van Assche multich = true;
3865d92c0da7SBart Van Assche }
3866d92c0da7SBart Van Assche
3867c257ea6fSBart Van Assche connected:
3868d92c0da7SBart Van Assche target->scsi_host->nr_hw_queues = target->ch_count;
3869aef9ec39SRoland Dreier
3870aef9ec39SRoland Dreier ret = srp_add_target(host, target);
3871aef9ec39SRoland Dreier if (ret)
3872aef9ec39SRoland Dreier goto err_disconnect;
3873aef9ec39SRoland Dreier
387434aa654eSBart Van Assche if (target->state != SRP_TARGET_REMOVED) {
387519f31343SBart Van Assche if (target->using_rdma_cm) {
387619f31343SBart Van Assche shost_printk(KERN_DEBUG, target->scsi_host, PFX
38777da09af9SBart Van Assche "new target: id_ext %016llx ioc_guid %016llx sgid %pI6 dest %pIS\n",
387819f31343SBart Van Assche be64_to_cpu(target->id_ext),
387919f31343SBart Van Assche be64_to_cpu(target->ioc_guid),
38807da09af9SBart Van Assche target->sgid.raw, &target->rdma_cm.dst);
388119f31343SBart Van Assche } else {
3882e7ffde01SBart Van Assche shost_printk(KERN_DEBUG, target->scsi_host, PFX
3883e7ffde01SBart Van Assche "new target: id_ext %016llx ioc_guid %016llx pkey %04x service_id %016llx sgid %pI6 dgid %pI6\n",
3884e7ffde01SBart Van Assche be64_to_cpu(target->id_ext),
3885e7ffde01SBart Van Assche be64_to_cpu(target->ioc_guid),
388619f31343SBart Van Assche be16_to_cpu(target->ib_cm.pkey),
388719f31343SBart Van Assche be64_to_cpu(target->ib_cm.service_id),
388819f31343SBart Van Assche target->sgid.raw,
388919f31343SBart Van Assche target->ib_cm.orig_dgid.raw);
389019f31343SBart Van Assche }
389134aa654eSBart Van Assche }
3892e7ffde01SBart Van Assche
38932d7091bcSBart Van Assche ret = count;
38942d7091bcSBart Van Assche
38952d7091bcSBart Van Assche out:
38962d7091bcSBart Van Assche mutex_unlock(&host->add_target_mutex);
389734aa654eSBart Van Assche
38984fa354c9SBart Van Assche put:
389934aa654eSBart Van Assche scsi_host_put(target->scsi_host);
390019f31343SBart Van Assche if (ret < 0) {
390119f31343SBart Van Assche /*
390219f31343SBart Van Assche * If a call to srp_remove_target() has not been scheduled,
390319f31343SBart Van Assche * drop the network namespace reference now that was obtained
390419f31343SBart Van Assche * earlier in this function.
390519f31343SBart Van Assche */
390619f31343SBart Van Assche if (target->state != SRP_TARGET_REMOVED)
390719f31343SBart Van Assche kobj_ns_drop(KOBJ_NS_TYPE_NET, target->net);
3908bc44bd1dSBart Van Assche scsi_host_put(target->scsi_host);
390919f31343SBart Van Assche }
391034aa654eSBart Van Assche
39112d7091bcSBart Van Assche return ret;
3912aef9ec39SRoland Dreier
3913aef9ec39SRoland Dreier err_disconnect:
3914aef9ec39SRoland Dreier srp_disconnect_target(target);
3915aef9ec39SRoland Dreier
3916b02c1536SBart Van Assche free_ch:
3917d92c0da7SBart Van Assche for (i = 0; i < target->ch_count; i++) {
3918d92c0da7SBart Van Assche ch = &target->ch[i];
3919509c07bcSBart Van Assche srp_free_ch_ib(target, ch);
3920d92c0da7SBart Van Assche }
3921d92c0da7SBart Van Assche
3922d92c0da7SBart Van Assche kfree(target->ch);
39232d7091bcSBart Van Assche goto out;
3924aef9ec39SRoland Dreier }
3925aef9ec39SRoland Dreier
392633e82346SYueHaibing static DEVICE_ATTR_WO(add_target);
3927aef9ec39SRoland Dreier
ibdev_show(struct device * dev,struct device_attribute * attr,char * buf)392833e82346SYueHaibing static ssize_t ibdev_show(struct device *dev, struct device_attribute *attr,
3929ee959b00STony Jones char *buf)
3930aef9ec39SRoland Dreier {
3931ee959b00STony Jones struct srp_host *host = container_of(dev, struct srp_host, dev);
3932aef9ec39SRoland Dreier
39331c7fd726SJoe Perches return sysfs_emit(buf, "%s\n", dev_name(&host->srp_dev->dev->dev));
3934aef9ec39SRoland Dreier }
3935aef9ec39SRoland Dreier
393633e82346SYueHaibing static DEVICE_ATTR_RO(ibdev);
3937aef9ec39SRoland Dreier
port_show(struct device * dev,struct device_attribute * attr,char * buf)393833e82346SYueHaibing static ssize_t port_show(struct device *dev, struct device_attribute *attr,
3939ee959b00STony Jones char *buf)
3940aef9ec39SRoland Dreier {
3941ee959b00STony Jones struct srp_host *host = container_of(dev, struct srp_host, dev);
3942aef9ec39SRoland Dreier
3943b05398afSMikhael Goikhman return sysfs_emit(buf, "%u\n", host->port);
3944aef9ec39SRoland Dreier }
3945aef9ec39SRoland Dreier
394633e82346SYueHaibing static DEVICE_ATTR_RO(port);
3947aef9ec39SRoland Dreier
3948b8a9c18cSBart Van Assche static struct attribute *srp_class_attrs[] = {
3949b8a9c18cSBart Van Assche &dev_attr_add_target.attr,
3950b8a9c18cSBart Van Assche &dev_attr_ibdev.attr,
3951b8a9c18cSBart Van Assche &dev_attr_port.attr,
3952b8a9c18cSBart Van Assche NULL
3953b8a9c18cSBart Van Assche };
3954b8a9c18cSBart Van Assche
srp_add_port(struct srp_device * device,u32 port)3955b05398afSMikhael Goikhman static struct srp_host *srp_add_port(struct srp_device *device, u32 port)
3956aef9ec39SRoland Dreier {
3957aef9ec39SRoland Dreier struct srp_host *host;
3958aef9ec39SRoland Dreier
3959aef9ec39SRoland Dreier host = kzalloc(sizeof *host, GFP_KERNEL);
3960aef9ec39SRoland Dreier if (!host)
3961aef9ec39SRoland Dreier return NULL;
3962aef9ec39SRoland Dreier
3963aef9ec39SRoland Dreier INIT_LIST_HEAD(&host->target_list);
3964b3589fd4SMatthew Wilcox spin_lock_init(&host->target_lock);
39652d7091bcSBart Van Assche mutex_init(&host->add_target_mutex);
396605321937SGreg Kroah-Hartman host->srp_dev = device;
3967aef9ec39SRoland Dreier host->port = port;
3968aef9ec39SRoland Dreier
3969351e458fSBart Van Assche device_initialize(&host->dev);
3970ee959b00STony Jones host->dev.class = &srp_class;
3971dee2b82aSBart Van Assche host->dev.parent = device->dev->dev.parent;
3972b05398afSMikhael Goikhman if (dev_set_name(&host->dev, "srp-%s-%u", dev_name(&device->dev->dev),
3973351e458fSBart Van Assche port))
3974351e458fSBart Van Assche goto put_host;
3975351e458fSBart Van Assche if (device_add(&host->dev))
3976c8e4c239SBart Van Assche goto put_host;
3977aef9ec39SRoland Dreier
3978aef9ec39SRoland Dreier return host;
3979aef9ec39SRoland Dreier
3980c8e4c239SBart Van Assche put_host:
3981c8e4c239SBart Van Assche put_device(&host->dev);
3982aef9ec39SRoland Dreier return NULL;
3983aef9ec39SRoland Dreier }
3984aef9ec39SRoland Dreier
srp_rename_dev(struct ib_device * device,void * client_data)3985dc1435c0SLeon Romanovsky static void srp_rename_dev(struct ib_device *device, void *client_data)
3986dc1435c0SLeon Romanovsky {
3987dc1435c0SLeon Romanovsky struct srp_device *srp_dev = client_data;
3988dc1435c0SLeon Romanovsky struct srp_host *host, *tmp_host;
3989dc1435c0SLeon Romanovsky
3990dc1435c0SLeon Romanovsky list_for_each_entry_safe(host, tmp_host, &srp_dev->dev_list, list) {
3991dc1435c0SLeon Romanovsky char name[IB_DEVICE_NAME_MAX + 8];
3992dc1435c0SLeon Romanovsky
3993b05398afSMikhael Goikhman snprintf(name, sizeof(name), "srp-%s-%u",
3994dc1435c0SLeon Romanovsky dev_name(&device->dev), host->port);
3995dc1435c0SLeon Romanovsky device_rename(&host->dev, name);
3996dc1435c0SLeon Romanovsky }
3997dc1435c0SLeon Romanovsky }
3998dc1435c0SLeon Romanovsky
srp_add_one(struct ib_device * device)399911a0ae4cSJason Gunthorpe static int srp_add_one(struct ib_device *device)
4000aef9ec39SRoland Dreier {
4001f5358a17SRoland Dreier struct srp_device *srp_dev;
4002042dd765SBart Van Assche struct ib_device_attr *attr = &device->attrs;
4003aef9ec39SRoland Dreier struct srp_host *host;
4004ea1075edSJason Gunthorpe int mr_page_shift;
4005b05398afSMikhael Goikhman u32 p;
400652ede08fSBart Van Assche u64 max_pages_per_mr;
40075f071777SChristoph Hellwig unsigned int flags = 0;
4008aef9ec39SRoland Dreier
4009249f0656SBart Van Assche srp_dev = kzalloc(sizeof(*srp_dev), GFP_KERNEL);
4010f5358a17SRoland Dreier if (!srp_dev)
401111a0ae4cSJason Gunthorpe return -ENOMEM;
4012f5358a17SRoland Dreier
4013f5358a17SRoland Dreier /*
4014f5358a17SRoland Dreier * Use the smallest page size supported by the HCA, down to a
40158f26c9ffSDavid Dillow * minimum of 4096 bytes. We're unlikely to build large sglists
40168f26c9ffSDavid Dillow * out of smaller entries.
4017f5358a17SRoland Dreier */
4018042dd765SBart Van Assche mr_page_shift = max(12, ffs(attr->page_size_cap) - 1);
401952ede08fSBart Van Assche srp_dev->mr_page_size = 1 << mr_page_shift;
402052ede08fSBart Van Assche srp_dev->mr_page_mask = ~((u64) srp_dev->mr_page_size - 1);
4021042dd765SBart Van Assche max_pages_per_mr = attr->max_mr_size;
402252ede08fSBart Van Assche do_div(max_pages_per_mr, srp_dev->mr_page_size);
4023509c5f33SBart Van Assche pr_debug("%s: %llu / %u = %llu <> %u\n", __func__,
4024042dd765SBart Van Assche attr->max_mr_size, srp_dev->mr_page_size,
4025509c5f33SBart Van Assche max_pages_per_mr, SRP_MAX_PAGES_PER_MR);
402652ede08fSBart Van Assche srp_dev->max_pages_per_mr = min_t(u64, SRP_MAX_PAGES_PER_MR,
402752ede08fSBart Van Assche max_pages_per_mr);
4028835ee624SBart Van Assche
4029042dd765SBart Van Assche srp_dev->has_fr = (attr->device_cap_flags &
4030835ee624SBart Van Assche IB_DEVICE_MEM_MGT_EXTENSIONS);
4031f273ad4fSMax Gurtovoy if (!never_register && !srp_dev->has_fr)
4032f273ad4fSMax Gurtovoy dev_warn(&device->dev, "FR is not supported\n");
4033f273ad4fSMax Gurtovoy else if (!never_register &&
4034f273ad4fSMax Gurtovoy attr->max_mr_size >= 2 * srp_dev->mr_page_size)
4035f273ad4fSMax Gurtovoy srp_dev->use_fast_reg = srp_dev->has_fr;
4036835ee624SBart Van Assche
4037f273ad4fSMax Gurtovoy if (never_register || !register_always || !srp_dev->has_fr)
40385f071777SChristoph Hellwig flags |= IB_PD_UNSAFE_GLOBAL_RKEY;
40395f071777SChristoph Hellwig
40405cfb1782SBart Van Assche if (srp_dev->use_fast_reg) {
40415cfb1782SBart Van Assche srp_dev->max_pages_per_mr =
40425cfb1782SBart Van Assche min_t(u32, srp_dev->max_pages_per_mr,
4043042dd765SBart Van Assche attr->max_fast_reg_page_list_len);
40445cfb1782SBart Van Assche }
404552ede08fSBart Van Assche srp_dev->mr_max_size = srp_dev->mr_page_size *
404652ede08fSBart Van Assche srp_dev->max_pages_per_mr;
40474a061b28SOr Gerlitz pr_debug("%s: mr_page_shift = %d, device->max_mr_size = %#llx, device->max_fast_reg_page_list_len = %u, max_pages_per_mr = %d, mr_max_size = %#x\n",
40486c854111SJason Gunthorpe dev_name(&device->dev), mr_page_shift, attr->max_mr_size,
4049042dd765SBart Van Assche attr->max_fast_reg_page_list_len,
405052ede08fSBart Van Assche srp_dev->max_pages_per_mr, srp_dev->mr_max_size);
4051f5358a17SRoland Dreier
4052f5358a17SRoland Dreier INIT_LIST_HEAD(&srp_dev->dev_list);
4053f5358a17SRoland Dreier
4054f5358a17SRoland Dreier srp_dev->dev = device;
40555f071777SChristoph Hellwig srp_dev->pd = ib_alloc_pd(device, flags);
405611a0ae4cSJason Gunthorpe if (IS_ERR(srp_dev->pd)) {
405711a0ae4cSJason Gunthorpe int ret = PTR_ERR(srp_dev->pd);
405811a0ae4cSJason Gunthorpe
405911a0ae4cSJason Gunthorpe kfree(srp_dev);
406011a0ae4cSJason Gunthorpe return ret;
406111a0ae4cSJason Gunthorpe }
4062f5358a17SRoland Dreier
4063cee687b6SBart Van Assche if (flags & IB_PD_UNSAFE_GLOBAL_RKEY) {
4064cee687b6SBart Van Assche srp_dev->global_rkey = srp_dev->pd->unsafe_global_rkey;
4065cee687b6SBart Van Assche WARN_ON_ONCE(srp_dev->global_rkey == 0);
4066cee687b6SBart Van Assche }
4067f5358a17SRoland Dreier
4068ea1075edSJason Gunthorpe rdma_for_each_port (device, p) {
4069f5358a17SRoland Dreier host = srp_add_port(srp_dev, p);
4070aef9ec39SRoland Dreier if (host)
4071f5358a17SRoland Dreier list_add_tail(&host->list, &srp_dev->dev_list);
4072aef9ec39SRoland Dreier }
4073aef9ec39SRoland Dreier
4074f5358a17SRoland Dreier ib_set_client_data(device, &srp_client, srp_dev);
407511a0ae4cSJason Gunthorpe return 0;
4076aef9ec39SRoland Dreier }
4077aef9ec39SRoland Dreier
srp_remove_one(struct ib_device * device,void * client_data)40787c1eb45aSHaggai Eran static void srp_remove_one(struct ib_device *device, void *client_data)
4079aef9ec39SRoland Dreier {
4080f5358a17SRoland Dreier struct srp_device *srp_dev;
4081aef9ec39SRoland Dreier struct srp_host *host, *tmp_host;
4082ef6c49d8SBart Van Assche struct srp_target_port *target;
4083aef9ec39SRoland Dreier
40847c1eb45aSHaggai Eran srp_dev = client_data;
4085aef9ec39SRoland Dreier
4086f5358a17SRoland Dreier list_for_each_entry_safe(host, tmp_host, &srp_dev->dev_list, list) {
4087aef9ec39SRoland Dreier /*
40880766fcaaSBart Van Assche * Remove the add_target sysfs entry so that no new target ports
40890766fcaaSBart Van Assche * can be created.
4090aef9ec39SRoland Dreier */
40910766fcaaSBart Van Assche device_del(&host->dev);
4092aef9ec39SRoland Dreier
4093aef9ec39SRoland Dreier /*
4094ef6c49d8SBart Van Assche * Remove all target ports.
4095aef9ec39SRoland Dreier */
4096b3589fd4SMatthew Wilcox spin_lock(&host->target_lock);
4097ef6c49d8SBart Van Assche list_for_each_entry(target, &host->target_list, list)
4098ef6c49d8SBart Van Assche srp_queue_remove_work(target);
4099b3589fd4SMatthew Wilcox spin_unlock(&host->target_lock);
4100aef9ec39SRoland Dreier
4101aef9ec39SRoland Dreier /*
4102081bdc9fSBart Van Assche * srp_queue_remove_work() queues a call to
4103081bdc9fSBart Van Assche * srp_remove_target(). The latter function cancels
4104081bdc9fSBart Van Assche * target->tl_err_work so waiting for the remove works to
4105081bdc9fSBart Van Assche * finish is sufficient.
4106aef9ec39SRoland Dreier */
4107bcc05910SBart Van Assche flush_workqueue(srp_remove_wq);
4108aef9ec39SRoland Dreier
41090766fcaaSBart Van Assche put_device(&host->dev);
4110aef9ec39SRoland Dreier }
4111aef9ec39SRoland Dreier
4112f5358a17SRoland Dreier ib_dealloc_pd(srp_dev->pd);
4113f5358a17SRoland Dreier
4114f5358a17SRoland Dreier kfree(srp_dev);
4115aef9ec39SRoland Dreier }
4116aef9ec39SRoland Dreier
41173236822bSFUJITA Tomonori static struct srp_function_template ib_srp_transport_functions = {
4118ed9b2264SBart Van Assche .has_rport_state = true,
4119ed9b2264SBart Van Assche .reset_timer_if_blocked = true,
4120a95cadb9SBart Van Assche .reconnect_delay = &srp_reconnect_delay,
4121ed9b2264SBart Van Assche .fast_io_fail_tmo = &srp_fast_io_fail_tmo,
4122ed9b2264SBart Van Assche .dev_loss_tmo = &srp_dev_loss_tmo,
4123ed9b2264SBart Van Assche .reconnect = srp_rport_reconnect,
4124dc1bdbd9SBart Van Assche .rport_delete = srp_rport_delete,
4125ed9b2264SBart Van Assche .terminate_rport_io = srp_terminate_io,
41263236822bSFUJITA Tomonori };
41273236822bSFUJITA Tomonori
srp_init_module(void)4128aef9ec39SRoland Dreier static int __init srp_init_module(void)
4129aef9ec39SRoland Dreier {
4130aef9ec39SRoland Dreier int ret;
4131aef9ec39SRoland Dreier
4132c838de1aSBart Van Assche BUILD_BUG_ON(sizeof(struct srp_aer_req) != 36);
4133c838de1aSBart Van Assche BUILD_BUG_ON(sizeof(struct srp_cmd) != 48);
413416d14e01SBart Van Assche BUILD_BUG_ON(sizeof(struct srp_imm_buf) != 4);
4135c838de1aSBart Van Assche BUILD_BUG_ON(sizeof(struct srp_indirect_buf) != 20);
413616d14e01SBart Van Assche BUILD_BUG_ON(sizeof(struct srp_login_req) != 64);
413716d14e01SBart Van Assche BUILD_BUG_ON(sizeof(struct srp_login_req_rdma) != 56);
4138c838de1aSBart Van Assche BUILD_BUG_ON(sizeof(struct srp_rsp) != 36);
413916d14e01SBart Van Assche
414049248644SDavid Dillow if (srp_sg_tablesize) {
4141e0bda7d8SBart Van Assche pr_warn("srp_sg_tablesize is deprecated, please use cmd_sg_entries\n");
414249248644SDavid Dillow if (!cmd_sg_entries)
414349248644SDavid Dillow cmd_sg_entries = srp_sg_tablesize;
414449248644SDavid Dillow }
414549248644SDavid Dillow
414649248644SDavid Dillow if (!cmd_sg_entries)
414749248644SDavid Dillow cmd_sg_entries = SRP_DEF_SG_TABLESIZE;
414849248644SDavid Dillow
414949248644SDavid Dillow if (cmd_sg_entries > 255) {
4150e0bda7d8SBart Van Assche pr_warn("Clamping cmd_sg_entries to 255\n");
415149248644SDavid Dillow cmd_sg_entries = 255;
41521e89a194SDavid Dillow }
41531e89a194SDavid Dillow
4154c07d424dSDavid Dillow if (!indirect_sg_entries)
4155c07d424dSDavid Dillow indirect_sg_entries = cmd_sg_entries;
4156c07d424dSDavid Dillow else if (indirect_sg_entries < cmd_sg_entries) {
4157e0bda7d8SBart Van Assche pr_warn("Bumping up indirect_sg_entries to match cmd_sg_entries (%u)\n",
4158e0bda7d8SBart Van Assche cmd_sg_entries);
4159c07d424dSDavid Dillow indirect_sg_entries = cmd_sg_entries;
4160c07d424dSDavid Dillow }
4161c07d424dSDavid Dillow
41620a475ef4SIsrael Rukshin if (indirect_sg_entries > SG_MAX_SEGMENTS) {
41630a475ef4SIsrael Rukshin pr_warn("Clamping indirect_sg_entries to %u\n",
41640a475ef4SIsrael Rukshin SG_MAX_SEGMENTS);
41650a475ef4SIsrael Rukshin indirect_sg_entries = SG_MAX_SEGMENTS;
41660a475ef4SIsrael Rukshin }
41670a475ef4SIsrael Rukshin
4168bcc05910SBart Van Assche srp_remove_wq = create_workqueue("srp_remove");
4169da05be29SWei Yongjun if (!srp_remove_wq) {
4170da05be29SWei Yongjun ret = -ENOMEM;
4171bcc05910SBart Van Assche goto out;
4172bcc05910SBart Van Assche }
4173bcc05910SBart Van Assche
4174bcc05910SBart Van Assche ret = -ENOMEM;
41753236822bSFUJITA Tomonori ib_srp_transport_template =
41763236822bSFUJITA Tomonori srp_attach_transport(&ib_srp_transport_functions);
41773236822bSFUJITA Tomonori if (!ib_srp_transport_template)
4178bcc05910SBart Van Assche goto destroy_wq;
41793236822bSFUJITA Tomonori
4180aef9ec39SRoland Dreier ret = class_register(&srp_class);
4181aef9ec39SRoland Dreier if (ret) {
4182e0bda7d8SBart Van Assche pr_err("couldn't register class infiniband_srp\n");
4183bcc05910SBart Van Assche goto release_tr;
4184aef9ec39SRoland Dreier }
4185aef9ec39SRoland Dreier
4186c1a0b23bSMichael S. Tsirkin ib_sa_register_client(&srp_sa_client);
4187c1a0b23bSMichael S. Tsirkin
4188aef9ec39SRoland Dreier ret = ib_register_client(&srp_client);
4189aef9ec39SRoland Dreier if (ret) {
4190e0bda7d8SBart Van Assche pr_err("couldn't register IB client\n");
4191bcc05910SBart Van Assche goto unreg_sa;
4192aef9ec39SRoland Dreier }
4193aef9ec39SRoland Dreier
4194bcc05910SBart Van Assche out:
4195bcc05910SBart Van Assche return ret;
4196bcc05910SBart Van Assche
4197bcc05910SBart Van Assche unreg_sa:
4198bcc05910SBart Van Assche ib_sa_unregister_client(&srp_sa_client);
4199bcc05910SBart Van Assche class_unregister(&srp_class);
4200bcc05910SBart Van Assche
4201bcc05910SBart Van Assche release_tr:
4202bcc05910SBart Van Assche srp_release_transport(ib_srp_transport_template);
4203bcc05910SBart Van Assche
4204bcc05910SBart Van Assche destroy_wq:
4205bcc05910SBart Van Assche destroy_workqueue(srp_remove_wq);
4206bcc05910SBart Van Assche goto out;
4207aef9ec39SRoland Dreier }
4208aef9ec39SRoland Dreier
srp_cleanup_module(void)4209aef9ec39SRoland Dreier static void __exit srp_cleanup_module(void)
4210aef9ec39SRoland Dreier {
4211aef9ec39SRoland Dreier ib_unregister_client(&srp_client);
4212c1a0b23bSMichael S. Tsirkin ib_sa_unregister_client(&srp_sa_client);
4213aef9ec39SRoland Dreier class_unregister(&srp_class);
42143236822bSFUJITA Tomonori srp_release_transport(ib_srp_transport_template);
4215bcc05910SBart Van Assche destroy_workqueue(srp_remove_wq);
4216aef9ec39SRoland Dreier }
4217aef9ec39SRoland Dreier
4218aef9ec39SRoland Dreier module_init(srp_init_module);
4219aef9ec39SRoland Dreier module_exit(srp_cleanup_module);
4220