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 33e0bda7d8SBart Van Assche #define pr_fmt(fmt) PFX fmt 34e0bda7d8SBart Van Assche 35aef9ec39SRoland Dreier #include <linux/module.h> 36aef9ec39SRoland Dreier #include <linux/init.h> 37aef9ec39SRoland Dreier #include <linux/slab.h> 38aef9ec39SRoland Dreier #include <linux/err.h> 39aef9ec39SRoland Dreier #include <linux/string.h> 40aef9ec39SRoland Dreier #include <linux/parser.h> 41aef9ec39SRoland Dreier #include <linux/random.h> 42de25968cSTim Schmielau #include <linux/jiffies.h> 43aef9ec39SRoland Dreier 4460063497SArun Sharma #include <linux/atomic.h> 45aef9ec39SRoland Dreier 46aef9ec39SRoland Dreier #include <scsi/scsi.h> 47aef9ec39SRoland Dreier #include <scsi/scsi_device.h> 48aef9ec39SRoland Dreier #include <scsi/scsi_dbg.h> 49aef9ec39SRoland Dreier #include <scsi/srp.h> 503236822bSFUJITA Tomonori #include <scsi/scsi_transport_srp.h> 51aef9ec39SRoland Dreier 52aef9ec39SRoland Dreier #include "ib_srp.h" 53aef9ec39SRoland Dreier 54aef9ec39SRoland Dreier #define DRV_NAME "ib_srp" 55aef9ec39SRoland Dreier #define PFX DRV_NAME ": " 56aef9ec39SRoland Dreier #define DRV_VERSION "0.2" 57aef9ec39SRoland Dreier #define DRV_RELDATE "November 1, 2005" 58aef9ec39SRoland Dreier 59aef9ec39SRoland Dreier MODULE_AUTHOR("Roland Dreier"); 60aef9ec39SRoland Dreier MODULE_DESCRIPTION("InfiniBand SCSI RDMA Protocol initiator " 61aef9ec39SRoland Dreier "v" DRV_VERSION " (" DRV_RELDATE ")"); 62aef9ec39SRoland Dreier MODULE_LICENSE("Dual BSD/GPL"); 63aef9ec39SRoland Dreier 6449248644SDavid Dillow static unsigned int srp_sg_tablesize; 6549248644SDavid Dillow static unsigned int cmd_sg_entries; 66c07d424dSDavid Dillow static unsigned int indirect_sg_entries; 67c07d424dSDavid Dillow static bool allow_ext_sg; 68aef9ec39SRoland Dreier static int topspin_workarounds = 1; 69aef9ec39SRoland Dreier 7049248644SDavid Dillow module_param(srp_sg_tablesize, uint, 0444); 7149248644SDavid Dillow MODULE_PARM_DESC(srp_sg_tablesize, "Deprecated name for cmd_sg_entries"); 7249248644SDavid Dillow 7349248644SDavid Dillow module_param(cmd_sg_entries, uint, 0444); 7449248644SDavid Dillow MODULE_PARM_DESC(cmd_sg_entries, 7549248644SDavid Dillow "Default number of gather/scatter entries in the SRP command (default is 12, max 255)"); 7649248644SDavid Dillow 77c07d424dSDavid Dillow module_param(indirect_sg_entries, uint, 0444); 78c07d424dSDavid Dillow MODULE_PARM_DESC(indirect_sg_entries, 79c07d424dSDavid Dillow "Default max number of gather/scatter entries (default is 12, max is " __stringify(SCSI_MAX_SG_CHAIN_SEGMENTS) ")"); 80c07d424dSDavid Dillow 81c07d424dSDavid Dillow module_param(allow_ext_sg, bool, 0444); 82c07d424dSDavid Dillow MODULE_PARM_DESC(allow_ext_sg, 83c07d424dSDavid Dillow "Default behavior when there are more than cmd_sg_entries S/G entries after mapping; fails the request when false (default false)"); 84c07d424dSDavid Dillow 85aef9ec39SRoland Dreier module_param(topspin_workarounds, int, 0444); 86aef9ec39SRoland Dreier MODULE_PARM_DESC(topspin_workarounds, 87aef9ec39SRoland Dreier "Enable workarounds for Topspin/Cisco SRP target bugs if != 0"); 88aef9ec39SRoland Dreier 89aef9ec39SRoland Dreier static void srp_add_one(struct ib_device *device); 90aef9ec39SRoland Dreier static void srp_remove_one(struct ib_device *device); 919c03dc9fSBart Van Assche static void srp_recv_completion(struct ib_cq *cq, void *target_ptr); 929c03dc9fSBart Van Assche static void srp_send_completion(struct ib_cq *cq, void *target_ptr); 93aef9ec39SRoland Dreier static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event); 94aef9ec39SRoland Dreier 953236822bSFUJITA Tomonori static struct scsi_transport_template *ib_srp_transport_template; 963236822bSFUJITA Tomonori 97aef9ec39SRoland Dreier static struct ib_client srp_client = { 98aef9ec39SRoland Dreier .name = "srp", 99aef9ec39SRoland Dreier .add = srp_add_one, 100aef9ec39SRoland Dreier .remove = srp_remove_one 101aef9ec39SRoland Dreier }; 102aef9ec39SRoland Dreier 103c1a0b23bSMichael S. Tsirkin static struct ib_sa_client srp_sa_client; 104c1a0b23bSMichael S. Tsirkin 105aef9ec39SRoland Dreier static inline struct srp_target_port *host_to_target(struct Scsi_Host *host) 106aef9ec39SRoland Dreier { 107aef9ec39SRoland Dreier return (struct srp_target_port *) host->hostdata; 108aef9ec39SRoland Dreier } 109aef9ec39SRoland Dreier 110aef9ec39SRoland Dreier static const char *srp_target_info(struct Scsi_Host *host) 111aef9ec39SRoland Dreier { 112aef9ec39SRoland Dreier return host_to_target(host)->target_name; 113aef9ec39SRoland Dreier } 114aef9ec39SRoland Dreier 1155d7cbfd6SRoland Dreier static int srp_target_is_topspin(struct srp_target_port *target) 1165d7cbfd6SRoland Dreier { 1175d7cbfd6SRoland Dreier static const u8 topspin_oui[3] = { 0x00, 0x05, 0xad }; 1183d1ff48dSRaghava Kondapalli static const u8 cisco_oui[3] = { 0x00, 0x1b, 0x0d }; 1195d7cbfd6SRoland Dreier 1205d7cbfd6SRoland Dreier return topspin_workarounds && 1213d1ff48dSRaghava Kondapalli (!memcmp(&target->ioc_guid, topspin_oui, sizeof topspin_oui) || 1223d1ff48dSRaghava Kondapalli !memcmp(&target->ioc_guid, cisco_oui, sizeof cisco_oui)); 1235d7cbfd6SRoland Dreier } 1245d7cbfd6SRoland Dreier 125aef9ec39SRoland Dreier static struct srp_iu *srp_alloc_iu(struct srp_host *host, size_t size, 126aef9ec39SRoland Dreier gfp_t gfp_mask, 127aef9ec39SRoland Dreier enum dma_data_direction direction) 128aef9ec39SRoland Dreier { 129aef9ec39SRoland Dreier struct srp_iu *iu; 130aef9ec39SRoland Dreier 131aef9ec39SRoland Dreier iu = kmalloc(sizeof *iu, gfp_mask); 132aef9ec39SRoland Dreier if (!iu) 133aef9ec39SRoland Dreier goto out; 134aef9ec39SRoland Dreier 135aef9ec39SRoland Dreier iu->buf = kzalloc(size, gfp_mask); 136aef9ec39SRoland Dreier if (!iu->buf) 137aef9ec39SRoland Dreier goto out_free_iu; 138aef9ec39SRoland Dreier 13905321937SGreg Kroah-Hartman iu->dma = ib_dma_map_single(host->srp_dev->dev, iu->buf, size, 14005321937SGreg Kroah-Hartman direction); 14105321937SGreg Kroah-Hartman if (ib_dma_mapping_error(host->srp_dev->dev, iu->dma)) 142aef9ec39SRoland Dreier goto out_free_buf; 143aef9ec39SRoland Dreier 144aef9ec39SRoland Dreier iu->size = size; 145aef9ec39SRoland Dreier iu->direction = direction; 146aef9ec39SRoland Dreier 147aef9ec39SRoland Dreier return iu; 148aef9ec39SRoland Dreier 149aef9ec39SRoland Dreier out_free_buf: 150aef9ec39SRoland Dreier kfree(iu->buf); 151aef9ec39SRoland Dreier out_free_iu: 152aef9ec39SRoland Dreier kfree(iu); 153aef9ec39SRoland Dreier out: 154aef9ec39SRoland Dreier return NULL; 155aef9ec39SRoland Dreier } 156aef9ec39SRoland Dreier 157aef9ec39SRoland Dreier static void srp_free_iu(struct srp_host *host, struct srp_iu *iu) 158aef9ec39SRoland Dreier { 159aef9ec39SRoland Dreier if (!iu) 160aef9ec39SRoland Dreier return; 161aef9ec39SRoland Dreier 16205321937SGreg Kroah-Hartman ib_dma_unmap_single(host->srp_dev->dev, iu->dma, iu->size, 16305321937SGreg Kroah-Hartman iu->direction); 164aef9ec39SRoland Dreier kfree(iu->buf); 165aef9ec39SRoland Dreier kfree(iu); 166aef9ec39SRoland Dreier } 167aef9ec39SRoland Dreier 168aef9ec39SRoland Dreier static void srp_qp_event(struct ib_event *event, void *context) 169aef9ec39SRoland Dreier { 170e0bda7d8SBart Van Assche pr_debug("QP event %d\n", event->event); 171aef9ec39SRoland Dreier } 172aef9ec39SRoland Dreier 173aef9ec39SRoland Dreier static int srp_init_qp(struct srp_target_port *target, 174aef9ec39SRoland Dreier struct ib_qp *qp) 175aef9ec39SRoland Dreier { 176aef9ec39SRoland Dreier struct ib_qp_attr *attr; 177aef9ec39SRoland Dreier int ret; 178aef9ec39SRoland Dreier 179aef9ec39SRoland Dreier attr = kmalloc(sizeof *attr, GFP_KERNEL); 180aef9ec39SRoland Dreier if (!attr) 181aef9ec39SRoland Dreier return -ENOMEM; 182aef9ec39SRoland Dreier 183969a60f9SRoland Dreier ret = ib_find_pkey(target->srp_host->srp_dev->dev, 184aef9ec39SRoland Dreier target->srp_host->port, 185aef9ec39SRoland Dreier be16_to_cpu(target->path.pkey), 186aef9ec39SRoland Dreier &attr->pkey_index); 187aef9ec39SRoland Dreier if (ret) 188aef9ec39SRoland Dreier goto out; 189aef9ec39SRoland Dreier 190aef9ec39SRoland Dreier attr->qp_state = IB_QPS_INIT; 191aef9ec39SRoland Dreier attr->qp_access_flags = (IB_ACCESS_REMOTE_READ | 192aef9ec39SRoland Dreier IB_ACCESS_REMOTE_WRITE); 193aef9ec39SRoland Dreier attr->port_num = target->srp_host->port; 194aef9ec39SRoland Dreier 195aef9ec39SRoland Dreier ret = ib_modify_qp(qp, attr, 196aef9ec39SRoland Dreier IB_QP_STATE | 197aef9ec39SRoland Dreier IB_QP_PKEY_INDEX | 198aef9ec39SRoland Dreier IB_QP_ACCESS_FLAGS | 199aef9ec39SRoland Dreier IB_QP_PORT); 200aef9ec39SRoland Dreier 201aef9ec39SRoland Dreier out: 202aef9ec39SRoland Dreier kfree(attr); 203aef9ec39SRoland Dreier return ret; 204aef9ec39SRoland Dreier } 205aef9ec39SRoland Dreier 2069fe4bcf4SDavid Dillow static int srp_new_cm_id(struct srp_target_port *target) 2079fe4bcf4SDavid Dillow { 2089fe4bcf4SDavid Dillow struct ib_cm_id *new_cm_id; 2099fe4bcf4SDavid Dillow 21005321937SGreg Kroah-Hartman new_cm_id = ib_create_cm_id(target->srp_host->srp_dev->dev, 2119fe4bcf4SDavid Dillow srp_cm_handler, target); 2129fe4bcf4SDavid Dillow if (IS_ERR(new_cm_id)) 2139fe4bcf4SDavid Dillow return PTR_ERR(new_cm_id); 2149fe4bcf4SDavid Dillow 2159fe4bcf4SDavid Dillow if (target->cm_id) 2169fe4bcf4SDavid Dillow ib_destroy_cm_id(target->cm_id); 2179fe4bcf4SDavid Dillow target->cm_id = new_cm_id; 2189fe4bcf4SDavid Dillow 2199fe4bcf4SDavid Dillow return 0; 2209fe4bcf4SDavid Dillow } 2219fe4bcf4SDavid Dillow 222aef9ec39SRoland Dreier static int srp_create_target_ib(struct srp_target_port *target) 223aef9ec39SRoland Dreier { 224aef9ec39SRoland Dreier struct ib_qp_init_attr *init_attr; 22573aa89edSIshai Rabinovitz struct ib_cq *recv_cq, *send_cq; 22673aa89edSIshai Rabinovitz struct ib_qp *qp; 227aef9ec39SRoland Dreier int ret; 228aef9ec39SRoland Dreier 229aef9ec39SRoland Dreier init_attr = kzalloc(sizeof *init_attr, GFP_KERNEL); 230aef9ec39SRoland Dreier if (!init_attr) 231aef9ec39SRoland Dreier return -ENOMEM; 232aef9ec39SRoland Dreier 23373aa89edSIshai Rabinovitz recv_cq = ib_create_cq(target->srp_host->srp_dev->dev, 2349c03dc9fSBart Van Assche srp_recv_completion, NULL, target, SRP_RQ_SIZE, 0); 23573aa89edSIshai Rabinovitz if (IS_ERR(recv_cq)) { 23673aa89edSIshai Rabinovitz ret = PTR_ERR(recv_cq); 237da9d2f07SRoland Dreier goto err; 238aef9ec39SRoland Dreier } 239aef9ec39SRoland Dreier 24073aa89edSIshai Rabinovitz send_cq = ib_create_cq(target->srp_host->srp_dev->dev, 2419c03dc9fSBart Van Assche srp_send_completion, NULL, target, SRP_SQ_SIZE, 0); 24273aa89edSIshai Rabinovitz if (IS_ERR(send_cq)) { 24373aa89edSIshai Rabinovitz ret = PTR_ERR(send_cq); 244da9d2f07SRoland Dreier goto err_recv_cq; 2459c03dc9fSBart Van Assche } 2469c03dc9fSBart Van Assche 24773aa89edSIshai Rabinovitz ib_req_notify_cq(recv_cq, IB_CQ_NEXT_COMP); 248aef9ec39SRoland Dreier 249aef9ec39SRoland Dreier init_attr->event_handler = srp_qp_event; 250aef9ec39SRoland Dreier init_attr->cap.max_send_wr = SRP_SQ_SIZE; 251aef9ec39SRoland Dreier init_attr->cap.max_recv_wr = SRP_RQ_SIZE; 252aef9ec39SRoland Dreier init_attr->cap.max_recv_sge = 1; 253aef9ec39SRoland Dreier init_attr->cap.max_send_sge = 1; 254aef9ec39SRoland Dreier init_attr->sq_sig_type = IB_SIGNAL_ALL_WR; 255aef9ec39SRoland Dreier init_attr->qp_type = IB_QPT_RC; 25673aa89edSIshai Rabinovitz init_attr->send_cq = send_cq; 25773aa89edSIshai Rabinovitz init_attr->recv_cq = recv_cq; 258aef9ec39SRoland Dreier 25973aa89edSIshai Rabinovitz qp = ib_create_qp(target->srp_host->srp_dev->pd, init_attr); 26073aa89edSIshai Rabinovitz if (IS_ERR(qp)) { 26173aa89edSIshai Rabinovitz ret = PTR_ERR(qp); 262da9d2f07SRoland Dreier goto err_send_cq; 263aef9ec39SRoland Dreier } 264aef9ec39SRoland Dreier 26573aa89edSIshai Rabinovitz ret = srp_init_qp(target, qp); 266da9d2f07SRoland Dreier if (ret) 267da9d2f07SRoland Dreier goto err_qp; 268aef9ec39SRoland Dreier 26973aa89edSIshai Rabinovitz if (target->qp) 27073aa89edSIshai Rabinovitz ib_destroy_qp(target->qp); 27173aa89edSIshai Rabinovitz if (target->recv_cq) 27273aa89edSIshai Rabinovitz ib_destroy_cq(target->recv_cq); 27373aa89edSIshai Rabinovitz if (target->send_cq) 27473aa89edSIshai Rabinovitz ib_destroy_cq(target->send_cq); 27573aa89edSIshai Rabinovitz 27673aa89edSIshai Rabinovitz target->qp = qp; 27773aa89edSIshai Rabinovitz target->recv_cq = recv_cq; 27873aa89edSIshai Rabinovitz target->send_cq = send_cq; 27973aa89edSIshai Rabinovitz 280da9d2f07SRoland Dreier kfree(init_attr); 281da9d2f07SRoland Dreier return 0; 282da9d2f07SRoland Dreier 283da9d2f07SRoland Dreier err_qp: 28473aa89edSIshai Rabinovitz ib_destroy_qp(qp); 285da9d2f07SRoland Dreier 286da9d2f07SRoland Dreier err_send_cq: 28773aa89edSIshai Rabinovitz ib_destroy_cq(send_cq); 288da9d2f07SRoland Dreier 289da9d2f07SRoland Dreier err_recv_cq: 29073aa89edSIshai Rabinovitz ib_destroy_cq(recv_cq); 291da9d2f07SRoland Dreier 292da9d2f07SRoland Dreier err: 293aef9ec39SRoland Dreier kfree(init_attr); 294aef9ec39SRoland Dreier return ret; 295aef9ec39SRoland Dreier } 296aef9ec39SRoland Dreier 297aef9ec39SRoland Dreier static void srp_free_target_ib(struct srp_target_port *target) 298aef9ec39SRoland Dreier { 299aef9ec39SRoland Dreier int i; 300aef9ec39SRoland Dreier 301aef9ec39SRoland Dreier ib_destroy_qp(target->qp); 3029c03dc9fSBart Van Assche ib_destroy_cq(target->send_cq); 3039c03dc9fSBart Van Assche ib_destroy_cq(target->recv_cq); 304aef9ec39SRoland Dreier 30573aa89edSIshai Rabinovitz target->qp = NULL; 30673aa89edSIshai Rabinovitz target->send_cq = target->recv_cq = NULL; 30773aa89edSIshai Rabinovitz 308aef9ec39SRoland Dreier for (i = 0; i < SRP_RQ_SIZE; ++i) 309aef9ec39SRoland Dreier srp_free_iu(target->srp_host, target->rx_ring[i]); 310dd5e6e38SBart Van Assche for (i = 0; i < SRP_SQ_SIZE; ++i) 311aef9ec39SRoland Dreier srp_free_iu(target->srp_host, target->tx_ring[i]); 312aef9ec39SRoland Dreier } 313aef9ec39SRoland Dreier 314aef9ec39SRoland Dreier static void srp_path_rec_completion(int status, 315aef9ec39SRoland Dreier struct ib_sa_path_rec *pathrec, 316aef9ec39SRoland Dreier void *target_ptr) 317aef9ec39SRoland Dreier { 318aef9ec39SRoland Dreier struct srp_target_port *target = target_ptr; 319aef9ec39SRoland Dreier 320aef9ec39SRoland Dreier target->status = status; 321aef9ec39SRoland Dreier if (status) 3227aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 3237aa54bd7SDavid Dillow PFX "Got failed path rec status %d\n", status); 324aef9ec39SRoland Dreier else 325aef9ec39SRoland Dreier target->path = *pathrec; 326aef9ec39SRoland Dreier complete(&target->done); 327aef9ec39SRoland Dreier } 328aef9ec39SRoland Dreier 329aef9ec39SRoland Dreier static int srp_lookup_path(struct srp_target_port *target) 330aef9ec39SRoland Dreier { 331aef9ec39SRoland Dreier target->path.numb_path = 1; 332aef9ec39SRoland Dreier 333aef9ec39SRoland Dreier init_completion(&target->done); 334aef9ec39SRoland Dreier 335c1a0b23bSMichael S. Tsirkin target->path_query_id = ib_sa_path_rec_get(&srp_sa_client, 33605321937SGreg Kroah-Hartman target->srp_host->srp_dev->dev, 337aef9ec39SRoland Dreier target->srp_host->port, 338aef9ec39SRoland Dreier &target->path, 339247e020eSSean Hefty IB_SA_PATH_REC_SERVICE_ID | 340aef9ec39SRoland Dreier IB_SA_PATH_REC_DGID | 341aef9ec39SRoland Dreier IB_SA_PATH_REC_SGID | 342aef9ec39SRoland Dreier IB_SA_PATH_REC_NUMB_PATH | 343aef9ec39SRoland Dreier IB_SA_PATH_REC_PKEY, 344aef9ec39SRoland Dreier SRP_PATH_REC_TIMEOUT_MS, 345aef9ec39SRoland Dreier GFP_KERNEL, 346aef9ec39SRoland Dreier srp_path_rec_completion, 347aef9ec39SRoland Dreier target, &target->path_query); 348aef9ec39SRoland Dreier if (target->path_query_id < 0) 349aef9ec39SRoland Dreier return target->path_query_id; 350aef9ec39SRoland Dreier 351aef9ec39SRoland Dreier wait_for_completion(&target->done); 352aef9ec39SRoland Dreier 353aef9ec39SRoland Dreier if (target->status < 0) 3547aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 3557aa54bd7SDavid Dillow PFX "Path record query failed\n"); 356aef9ec39SRoland Dreier 357aef9ec39SRoland Dreier return target->status; 358aef9ec39SRoland Dreier } 359aef9ec39SRoland Dreier 360aef9ec39SRoland Dreier static int srp_send_req(struct srp_target_port *target) 361aef9ec39SRoland Dreier { 362aef9ec39SRoland Dreier struct { 363aef9ec39SRoland Dreier struct ib_cm_req_param param; 364aef9ec39SRoland Dreier struct srp_login_req priv; 365aef9ec39SRoland Dreier } *req = NULL; 366aef9ec39SRoland Dreier int status; 367aef9ec39SRoland Dreier 368aef9ec39SRoland Dreier req = kzalloc(sizeof *req, GFP_KERNEL); 369aef9ec39SRoland Dreier if (!req) 370aef9ec39SRoland Dreier return -ENOMEM; 371aef9ec39SRoland Dreier 372aef9ec39SRoland Dreier req->param.primary_path = &target->path; 373aef9ec39SRoland Dreier req->param.alternate_path = NULL; 374aef9ec39SRoland Dreier req->param.service_id = target->service_id; 375aef9ec39SRoland Dreier req->param.qp_num = target->qp->qp_num; 376aef9ec39SRoland Dreier req->param.qp_type = target->qp->qp_type; 377aef9ec39SRoland Dreier req->param.private_data = &req->priv; 378aef9ec39SRoland Dreier req->param.private_data_len = sizeof req->priv; 379aef9ec39SRoland Dreier req->param.flow_control = 1; 380aef9ec39SRoland Dreier 381aef9ec39SRoland Dreier get_random_bytes(&req->param.starting_psn, 4); 382aef9ec39SRoland Dreier req->param.starting_psn &= 0xffffff; 383aef9ec39SRoland Dreier 384aef9ec39SRoland Dreier /* 385aef9ec39SRoland Dreier * Pick some arbitrary defaults here; we could make these 386aef9ec39SRoland Dreier * module parameters if anyone cared about setting them. 387aef9ec39SRoland Dreier */ 388aef9ec39SRoland Dreier req->param.responder_resources = 4; 389aef9ec39SRoland Dreier req->param.remote_cm_response_timeout = 20; 390aef9ec39SRoland Dreier req->param.local_cm_response_timeout = 20; 391aef9ec39SRoland Dreier req->param.retry_count = 7; 392aef9ec39SRoland Dreier req->param.rnr_retry_count = 7; 393aef9ec39SRoland Dreier req->param.max_cm_retries = 15; 394aef9ec39SRoland Dreier 395aef9ec39SRoland Dreier req->priv.opcode = SRP_LOGIN_REQ; 396aef9ec39SRoland Dreier req->priv.tag = 0; 39749248644SDavid Dillow req->priv.req_it_iu_len = cpu_to_be32(target->max_iu_len); 398aef9ec39SRoland Dreier req->priv.req_buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT | 399aef9ec39SRoland Dreier SRP_BUF_FORMAT_INDIRECT); 4000c0450dbSRamachandra K /* 4010c0450dbSRamachandra K * In the published SRP specification (draft rev. 16a), the 4020c0450dbSRamachandra K * port identifier format is 8 bytes of ID extension followed 4030c0450dbSRamachandra K * by 8 bytes of GUID. Older drafts put the two halves in the 4040c0450dbSRamachandra K * opposite order, so that the GUID comes first. 4050c0450dbSRamachandra K * 4060c0450dbSRamachandra K * Targets conforming to these obsolete drafts can be 4070c0450dbSRamachandra K * recognized by the I/O Class they report. 4080c0450dbSRamachandra K */ 4090c0450dbSRamachandra K if (target->io_class == SRP_REV10_IB_IO_CLASS) { 4100c0450dbSRamachandra K memcpy(req->priv.initiator_port_id, 41101cb9bcbSIshai Rabinovitz &target->path.sgid.global.interface_id, 8); 4120c0450dbSRamachandra K memcpy(req->priv.initiator_port_id + 8, 41301cb9bcbSIshai Rabinovitz &target->initiator_ext, 8); 4140c0450dbSRamachandra K memcpy(req->priv.target_port_id, &target->ioc_guid, 8); 4150c0450dbSRamachandra K memcpy(req->priv.target_port_id + 8, &target->id_ext, 8); 4160c0450dbSRamachandra K } else { 4170c0450dbSRamachandra K memcpy(req->priv.initiator_port_id, 41801cb9bcbSIshai Rabinovitz &target->initiator_ext, 8); 41901cb9bcbSIshai Rabinovitz memcpy(req->priv.initiator_port_id + 8, 42001cb9bcbSIshai Rabinovitz &target->path.sgid.global.interface_id, 8); 4210c0450dbSRamachandra K memcpy(req->priv.target_port_id, &target->id_ext, 8); 4220c0450dbSRamachandra K memcpy(req->priv.target_port_id + 8, &target->ioc_guid, 8); 4230c0450dbSRamachandra K } 4240c0450dbSRamachandra K 425aef9ec39SRoland Dreier /* 426aef9ec39SRoland Dreier * Topspin/Cisco SRP targets will reject our login unless we 42701cb9bcbSIshai Rabinovitz * zero out the first 8 bytes of our initiator port ID and set 42801cb9bcbSIshai Rabinovitz * the second 8 bytes to the local node GUID. 429aef9ec39SRoland Dreier */ 4305d7cbfd6SRoland Dreier if (srp_target_is_topspin(target)) { 4317aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, target->scsi_host, 4327aa54bd7SDavid Dillow PFX "Topspin/Cisco initiator port ID workaround " 433aef9ec39SRoland Dreier "activated for target GUID %016llx\n", 434aef9ec39SRoland Dreier (unsigned long long) be64_to_cpu(target->ioc_guid)); 435aef9ec39SRoland Dreier memset(req->priv.initiator_port_id, 0, 8); 43601cb9bcbSIshai Rabinovitz memcpy(req->priv.initiator_port_id + 8, 43705321937SGreg Kroah-Hartman &target->srp_host->srp_dev->dev->node_guid, 8); 438aef9ec39SRoland Dreier } 439aef9ec39SRoland Dreier 440aef9ec39SRoland Dreier status = ib_send_cm_req(target->cm_id, &req->param); 441aef9ec39SRoland Dreier 442aef9ec39SRoland Dreier kfree(req); 443aef9ec39SRoland Dreier 444aef9ec39SRoland Dreier return status; 445aef9ec39SRoland Dreier } 446aef9ec39SRoland Dreier 447ef6c49d8SBart Van Assche static bool srp_queue_remove_work(struct srp_target_port *target) 448ef6c49d8SBart Van Assche { 449ef6c49d8SBart Van Assche bool changed = false; 450ef6c49d8SBart Van Assche 451ef6c49d8SBart Van Assche spin_lock_irq(&target->lock); 452ef6c49d8SBart Van Assche if (target->state != SRP_TARGET_REMOVED) { 453ef6c49d8SBart Van Assche target->state = SRP_TARGET_REMOVED; 454ef6c49d8SBart Van Assche changed = true; 455ef6c49d8SBart Van Assche } 456ef6c49d8SBart Van Assche spin_unlock_irq(&target->lock); 457ef6c49d8SBart Van Assche 458ef6c49d8SBart Van Assche if (changed) 459ef6c49d8SBart Van Assche queue_work(system_long_wq, &target->remove_work); 460ef6c49d8SBart Van Assche 461ef6c49d8SBart Van Assche return changed; 462ef6c49d8SBart Van Assche } 463ef6c49d8SBart Van Assche 464294c875aSBart Van Assche static bool srp_change_conn_state(struct srp_target_port *target, 465294c875aSBart Van Assche bool connected) 466294c875aSBart Van Assche { 467294c875aSBart Van Assche bool changed = false; 468294c875aSBart Van Assche 469294c875aSBart Van Assche spin_lock_irq(&target->lock); 470294c875aSBart Van Assche if (target->connected != connected) { 471294c875aSBart Van Assche target->connected = connected; 472294c875aSBart Van Assche changed = true; 473294c875aSBart Van Assche } 474294c875aSBart Van Assche spin_unlock_irq(&target->lock); 475294c875aSBart Van Assche 476294c875aSBart Van Assche return changed; 477294c875aSBart Van Assche } 478294c875aSBart Van Assche 479aef9ec39SRoland Dreier static void srp_disconnect_target(struct srp_target_port *target) 480aef9ec39SRoland Dreier { 481294c875aSBart Van Assche if (srp_change_conn_state(target, false)) { 482aef9ec39SRoland Dreier /* XXX should send SRP_I_LOGOUT request */ 483aef9ec39SRoland Dreier 484e6581056SRoland Dreier if (ib_send_cm_dreq(target->cm_id, NULL, 0)) { 4857aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, target->scsi_host, 4867aa54bd7SDavid Dillow PFX "Sending CM DREQ failed\n"); 487aef9ec39SRoland Dreier } 488294c875aSBart Van Assche } 489294c875aSBart Van Assche } 490aef9ec39SRoland Dreier 4918f26c9ffSDavid Dillow static void srp_free_req_data(struct srp_target_port *target) 4928f26c9ffSDavid Dillow { 493c07d424dSDavid Dillow struct ib_device *ibdev = target->srp_host->srp_dev->dev; 4948f26c9ffSDavid Dillow struct srp_request *req; 4958f26c9ffSDavid Dillow int i; 4968f26c9ffSDavid Dillow 4978f26c9ffSDavid Dillow for (i = 0, req = target->req_ring; i < SRP_CMD_SQ_SIZE; ++i, ++req) { 4988f26c9ffSDavid Dillow kfree(req->fmr_list); 4998f26c9ffSDavid Dillow kfree(req->map_page); 500c07d424dSDavid Dillow if (req->indirect_dma_addr) { 501c07d424dSDavid Dillow ib_dma_unmap_single(ibdev, req->indirect_dma_addr, 502c07d424dSDavid Dillow target->indirect_size, 503c07d424dSDavid Dillow DMA_TO_DEVICE); 504c07d424dSDavid Dillow } 505c07d424dSDavid Dillow kfree(req->indirect_desc); 5068f26c9ffSDavid Dillow } 5078f26c9ffSDavid Dillow } 5088f26c9ffSDavid Dillow 509683b159aSBart Van Assche /** 510683b159aSBart Van Assche * srp_del_scsi_host_attr() - Remove attributes defined in the host template. 511683b159aSBart Van Assche * @shost: SCSI host whose attributes to remove from sysfs. 512683b159aSBart Van Assche * 513683b159aSBart Van Assche * Note: Any attributes defined in the host template and that did not exist 514683b159aSBart Van Assche * before invocation of this function will be ignored. 515683b159aSBart Van Assche */ 516683b159aSBart Van Assche static void srp_del_scsi_host_attr(struct Scsi_Host *shost) 517683b159aSBart Van Assche { 518683b159aSBart Van Assche struct device_attribute **attr; 519683b159aSBart Van Assche 520683b159aSBart Van Assche for (attr = shost->hostt->shost_attrs; attr && *attr; ++attr) 521683b159aSBart Van Assche device_remove_file(&shost->shost_dev, *attr); 522683b159aSBart Van Assche } 523683b159aSBart Van Assche 524ee12d6a8SBart Van Assche static void srp_remove_target(struct srp_target_port *target) 525ee12d6a8SBart Van Assche { 526ef6c49d8SBart Van Assche WARN_ON_ONCE(target->state != SRP_TARGET_REMOVED); 527ef6c49d8SBart Van Assche 528ee12d6a8SBart Van Assche srp_del_scsi_host_attr(target->scsi_host); 529ee12d6a8SBart Van Assche srp_remove_host(target->scsi_host); 530ee12d6a8SBart Van Assche scsi_remove_host(target->scsi_host); 531ef6c49d8SBart Van Assche srp_disconnect_target(target); 532ee12d6a8SBart Van Assche ib_destroy_cm_id(target->cm_id); 533ee12d6a8SBart Van Assche srp_free_target_ib(target); 534ee12d6a8SBart Van Assche srp_free_req_data(target); 535ee12d6a8SBart Van Assche scsi_host_put(target->scsi_host); 536ee12d6a8SBart Van Assche } 537ee12d6a8SBart Van Assche 538c4028958SDavid Howells static void srp_remove_work(struct work_struct *work) 539aef9ec39SRoland Dreier { 540c4028958SDavid Howells struct srp_target_port *target = 541ef6c49d8SBart Van Assche container_of(work, struct srp_target_port, remove_work); 542aef9ec39SRoland Dreier 543ef6c49d8SBart Van Assche WARN_ON_ONCE(target->state != SRP_TARGET_REMOVED); 544aef9ec39SRoland Dreier 545b3589fd4SMatthew Wilcox spin_lock(&target->srp_host->target_lock); 546aef9ec39SRoland Dreier list_del(&target->list); 547b3589fd4SMatthew Wilcox spin_unlock(&target->srp_host->target_lock); 548aef9ec39SRoland Dreier 549ee12d6a8SBart Van Assche srp_remove_target(target); 550aef9ec39SRoland Dreier } 551aef9ec39SRoland Dreier 552*dc1bdbd9SBart Van Assche static void srp_rport_delete(struct srp_rport *rport) 553*dc1bdbd9SBart Van Assche { 554*dc1bdbd9SBart Van Assche struct srp_target_port *target = rport->lld_data; 555*dc1bdbd9SBart Van Assche 556*dc1bdbd9SBart Van Assche srp_queue_remove_work(target); 557*dc1bdbd9SBart Van Assche } 558*dc1bdbd9SBart Van Assche 559aef9ec39SRoland Dreier static int srp_connect_target(struct srp_target_port *target) 560aef9ec39SRoland Dreier { 5619fe4bcf4SDavid Dillow int retries = 3; 562aef9ec39SRoland Dreier int ret; 563aef9ec39SRoland Dreier 564294c875aSBart Van Assche WARN_ON_ONCE(target->connected); 565294c875aSBart Van Assche 566948d1e88SBart Van Assche target->qp_in_error = false; 567948d1e88SBart Van Assche 568aef9ec39SRoland Dreier ret = srp_lookup_path(target); 569aef9ec39SRoland Dreier if (ret) 570aef9ec39SRoland Dreier return ret; 571aef9ec39SRoland Dreier 572aef9ec39SRoland Dreier while (1) { 573aef9ec39SRoland Dreier init_completion(&target->done); 574aef9ec39SRoland Dreier ret = srp_send_req(target); 575aef9ec39SRoland Dreier if (ret) 576aef9ec39SRoland Dreier return ret; 577aef9ec39SRoland Dreier wait_for_completion(&target->done); 578aef9ec39SRoland Dreier 579aef9ec39SRoland Dreier /* 580aef9ec39SRoland Dreier * The CM event handling code will set status to 581aef9ec39SRoland Dreier * SRP_PORT_REDIRECT if we get a port redirect REJ 582aef9ec39SRoland Dreier * back, or SRP_DLID_REDIRECT if we get a lid/qp 583aef9ec39SRoland Dreier * redirect REJ back. 584aef9ec39SRoland Dreier */ 585aef9ec39SRoland Dreier switch (target->status) { 586aef9ec39SRoland Dreier case 0: 587294c875aSBart Van Assche srp_change_conn_state(target, true); 588aef9ec39SRoland Dreier return 0; 589aef9ec39SRoland Dreier 590aef9ec39SRoland Dreier case SRP_PORT_REDIRECT: 591aef9ec39SRoland Dreier ret = srp_lookup_path(target); 592aef9ec39SRoland Dreier if (ret) 593aef9ec39SRoland Dreier return ret; 594aef9ec39SRoland Dreier break; 595aef9ec39SRoland Dreier 596aef9ec39SRoland Dreier case SRP_DLID_REDIRECT: 597aef9ec39SRoland Dreier break; 598aef9ec39SRoland Dreier 5999fe4bcf4SDavid Dillow case SRP_STALE_CONN: 6009fe4bcf4SDavid Dillow /* Our current CM id was stale, and is now in timewait. 6019fe4bcf4SDavid Dillow * Try to reconnect with a new one. 6029fe4bcf4SDavid Dillow */ 6039fe4bcf4SDavid Dillow if (!retries-- || srp_new_cm_id(target)) { 6049fe4bcf4SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX 6059fe4bcf4SDavid Dillow "giving up on stale connection\n"); 6069fe4bcf4SDavid Dillow target->status = -ECONNRESET; 6079fe4bcf4SDavid Dillow return target->status; 6089fe4bcf4SDavid Dillow } 6099fe4bcf4SDavid Dillow 6109fe4bcf4SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX 6119fe4bcf4SDavid Dillow "retrying stale connection\n"); 6129fe4bcf4SDavid Dillow break; 6139fe4bcf4SDavid Dillow 614aef9ec39SRoland Dreier default: 615aef9ec39SRoland Dreier return target->status; 616aef9ec39SRoland Dreier } 617aef9ec39SRoland Dreier } 618aef9ec39SRoland Dreier } 619aef9ec39SRoland Dreier 620d945e1dfSRoland Dreier static void srp_unmap_data(struct scsi_cmnd *scmnd, 621d945e1dfSRoland Dreier struct srp_target_port *target, 622d945e1dfSRoland Dreier struct srp_request *req) 623d945e1dfSRoland Dreier { 6248f26c9ffSDavid Dillow struct ib_device *ibdev = target->srp_host->srp_dev->dev; 6258f26c9ffSDavid Dillow struct ib_pool_fmr **pfmr; 6268f26c9ffSDavid Dillow 627bb350d1dSFUJITA Tomonori if (!scsi_sglist(scmnd) || 628d945e1dfSRoland Dreier (scmnd->sc_data_direction != DMA_TO_DEVICE && 629d945e1dfSRoland Dreier scmnd->sc_data_direction != DMA_FROM_DEVICE)) 630d945e1dfSRoland Dreier return; 631d945e1dfSRoland Dreier 6328f26c9ffSDavid Dillow pfmr = req->fmr_list; 6338f26c9ffSDavid Dillow while (req->nfmr--) 6348f26c9ffSDavid Dillow ib_fmr_pool_unmap(*pfmr++); 635f5358a17SRoland Dreier 6368f26c9ffSDavid Dillow ib_dma_unmap_sg(ibdev, scsi_sglist(scmnd), scsi_sg_count(scmnd), 6378f26c9ffSDavid Dillow scmnd->sc_data_direction); 638d945e1dfSRoland Dreier } 639d945e1dfSRoland Dreier 64022032991SBart Van Assche /** 64122032991SBart Van Assche * srp_claim_req - Take ownership of the scmnd associated with a request. 64222032991SBart Van Assche * @target: SRP target port. 64322032991SBart Van Assche * @req: SRP request. 64422032991SBart Van Assche * @scmnd: If NULL, take ownership of @req->scmnd. If not NULL, only take 64522032991SBart Van Assche * ownership of @req->scmnd if it equals @scmnd. 64622032991SBart Van Assche * 64722032991SBart Van Assche * Return value: 64822032991SBart Van Assche * Either NULL or a pointer to the SCSI command the caller became owner of. 64922032991SBart Van Assche */ 65022032991SBart Van Assche static struct scsi_cmnd *srp_claim_req(struct srp_target_port *target, 65122032991SBart Van Assche struct srp_request *req, 65222032991SBart Van Assche struct scsi_cmnd *scmnd) 653526b4caaSIshai Rabinovitz { 65494a9174cSBart Van Assche unsigned long flags; 65594a9174cSBart Van Assche 65622032991SBart Van Assche spin_lock_irqsave(&target->lock, flags); 65722032991SBart Van Assche if (!scmnd) { 65822032991SBart Van Assche scmnd = req->scmnd; 65922032991SBart Van Assche req->scmnd = NULL; 66022032991SBart Van Assche } else if (req->scmnd == scmnd) { 66122032991SBart Van Assche req->scmnd = NULL; 66222032991SBart Van Assche } else { 66322032991SBart Van Assche scmnd = NULL; 66422032991SBart Van Assche } 66522032991SBart Van Assche spin_unlock_irqrestore(&target->lock, flags); 66622032991SBart Van Assche 66722032991SBart Van Assche return scmnd; 66822032991SBart Van Assche } 66922032991SBart Van Assche 67022032991SBart Van Assche /** 67122032991SBart Van Assche * srp_free_req() - Unmap data and add request to the free request list. 67222032991SBart Van Assche */ 67322032991SBart Van Assche static void srp_free_req(struct srp_target_port *target, 67422032991SBart Van Assche struct srp_request *req, struct scsi_cmnd *scmnd, 67522032991SBart Van Assche s32 req_lim_delta) 67622032991SBart Van Assche { 67722032991SBart Van Assche unsigned long flags; 67822032991SBart Van Assche 67922032991SBart Van Assche srp_unmap_data(scmnd, target, req); 68022032991SBart Van Assche 681e9684678SBart Van Assche spin_lock_irqsave(&target->lock, flags); 68294a9174cSBart Van Assche target->req_lim += req_lim_delta; 683536ae14eSBart Van Assche list_add_tail(&req->list, &target->free_reqs); 684e9684678SBart Van Assche spin_unlock_irqrestore(&target->lock, flags); 685526b4caaSIshai Rabinovitz } 686526b4caaSIshai Rabinovitz 687526b4caaSIshai Rabinovitz static void srp_reset_req(struct srp_target_port *target, struct srp_request *req) 688526b4caaSIshai Rabinovitz { 68922032991SBart Van Assche struct scsi_cmnd *scmnd = srp_claim_req(target, req, NULL); 69022032991SBart Van Assche 69122032991SBart Van Assche if (scmnd) { 6929b796d06SBart Van Assche srp_free_req(target, req, scmnd, 0); 69322032991SBart Van Assche scmnd->result = DID_RESET << 16; 69422032991SBart Van Assche scmnd->scsi_done(scmnd); 69522032991SBart Van Assche } 696526b4caaSIshai Rabinovitz } 697526b4caaSIshai Rabinovitz 698aef9ec39SRoland Dreier static int srp_reconnect_target(struct srp_target_port *target) 699aef9ec39SRoland Dreier { 70009be70a2SBart Van Assche struct Scsi_Host *shost = target->scsi_host; 701dcb4cb85SBart Van Assche int i, ret; 702aef9ec39SRoland Dreier 70309be70a2SBart Van Assche if (target->state != SRP_TARGET_LIVE) 704aef9ec39SRoland Dreier return -EAGAIN; 705aef9ec39SRoland Dreier 70609be70a2SBart Van Assche scsi_target_block(&shost->shost_gendev); 70709be70a2SBart Van Assche 708aef9ec39SRoland Dreier srp_disconnect_target(target); 709aef9ec39SRoland Dreier /* 710aef9ec39SRoland Dreier * Now get a new local CM ID so that we avoid confusing the 711aef9ec39SRoland Dreier * target in case things are really fouled up. 712aef9ec39SRoland Dreier */ 7139fe4bcf4SDavid Dillow ret = srp_new_cm_id(target); 7149fe4bcf4SDavid Dillow if (ret) 71509be70a2SBart Van Assche goto unblock; 716aef9ec39SRoland Dreier 71773aa89edSIshai Rabinovitz ret = srp_create_target_ib(target); 718aef9ec39SRoland Dreier if (ret) 71909be70a2SBart Van Assche goto unblock; 720aef9ec39SRoland Dreier 721536ae14eSBart Van Assche for (i = 0; i < SRP_CMD_SQ_SIZE; ++i) { 722536ae14eSBart Van Assche struct srp_request *req = &target->req_ring[i]; 723536ae14eSBart Van Assche if (req->scmnd) 724526b4caaSIshai Rabinovitz srp_reset_req(target, req); 725536ae14eSBart Van Assche } 726aef9ec39SRoland Dreier 727536ae14eSBart Van Assche INIT_LIST_HEAD(&target->free_tx); 728dcb4cb85SBart Van Assche for (i = 0; i < SRP_SQ_SIZE; ++i) 729536ae14eSBart Van Assche list_add(&target->tx_ring[i]->list, &target->free_tx); 730aef9ec39SRoland Dreier 731aef9ec39SRoland Dreier ret = srp_connect_target(target); 73209be70a2SBart Van Assche 73309be70a2SBart Van Assche unblock: 73409be70a2SBart Van Assche scsi_target_unblock(&shost->shost_gendev, ret == 0 ? SDEV_RUNNING : 73509be70a2SBart Van Assche SDEV_TRANSPORT_OFFLINE); 73609be70a2SBart Van Assche 737aef9ec39SRoland Dreier if (ret) 738aef9ec39SRoland Dreier goto err; 739aef9ec39SRoland Dreier 74009be70a2SBart Van Assche shost_printk(KERN_INFO, target->scsi_host, PFX "reconnect succeeded\n"); 741aef9ec39SRoland Dreier 742aef9ec39SRoland Dreier return ret; 743aef9ec39SRoland Dreier 744aef9ec39SRoland Dreier err: 7457aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 7467aa54bd7SDavid Dillow PFX "reconnect failed (%d), removing target port.\n", ret); 747aef9ec39SRoland Dreier 748aef9ec39SRoland Dreier /* 749aef9ec39SRoland Dreier * We couldn't reconnect, so kill our target port off. 7509709f0e0SBart Van Assche * However, we have to defer the real removal because we 7519709f0e0SBart Van Assche * are in the context of the SCSI error handler now, which 7529709f0e0SBart Van Assche * will deadlock if we call scsi_remove_host(). 753aef9ec39SRoland Dreier */ 754ef6c49d8SBart Van Assche srp_queue_remove_work(target); 755aef9ec39SRoland Dreier 756aef9ec39SRoland Dreier return ret; 757aef9ec39SRoland Dreier } 758aef9ec39SRoland Dreier 7598f26c9ffSDavid Dillow static void srp_map_desc(struct srp_map_state *state, dma_addr_t dma_addr, 7608f26c9ffSDavid Dillow unsigned int dma_len, u32 rkey) 761f5358a17SRoland Dreier { 7628f26c9ffSDavid Dillow struct srp_direct_buf *desc = state->desc; 7638f26c9ffSDavid Dillow 7648f26c9ffSDavid Dillow desc->va = cpu_to_be64(dma_addr); 7658f26c9ffSDavid Dillow desc->key = cpu_to_be32(rkey); 7668f26c9ffSDavid Dillow desc->len = cpu_to_be32(dma_len); 7678f26c9ffSDavid Dillow 7688f26c9ffSDavid Dillow state->total_len += dma_len; 7698f26c9ffSDavid Dillow state->desc++; 7708f26c9ffSDavid Dillow state->ndesc++; 7718f26c9ffSDavid Dillow } 7728f26c9ffSDavid Dillow 7738f26c9ffSDavid Dillow static int srp_map_finish_fmr(struct srp_map_state *state, 7748f26c9ffSDavid Dillow struct srp_target_port *target) 7758f26c9ffSDavid Dillow { 7768f26c9ffSDavid Dillow struct srp_device *dev = target->srp_host->srp_dev; 7778f26c9ffSDavid Dillow struct ib_pool_fmr *fmr; 778f5358a17SRoland Dreier u64 io_addr = 0; 7798f26c9ffSDavid Dillow 7808f26c9ffSDavid Dillow if (!state->npages) 7818f26c9ffSDavid Dillow return 0; 7828f26c9ffSDavid Dillow 7838f26c9ffSDavid Dillow if (state->npages == 1) { 7848f26c9ffSDavid Dillow srp_map_desc(state, state->base_dma_addr, state->fmr_len, 7858f26c9ffSDavid Dillow target->rkey); 7868f26c9ffSDavid Dillow state->npages = state->fmr_len = 0; 7878f26c9ffSDavid Dillow return 0; 7888f26c9ffSDavid Dillow } 7898f26c9ffSDavid Dillow 7908f26c9ffSDavid Dillow fmr = ib_fmr_pool_map_phys(dev->fmr_pool, state->pages, 7918f26c9ffSDavid Dillow state->npages, io_addr); 7928f26c9ffSDavid Dillow if (IS_ERR(fmr)) 7938f26c9ffSDavid Dillow return PTR_ERR(fmr); 7948f26c9ffSDavid Dillow 7958f26c9ffSDavid Dillow *state->next_fmr++ = fmr; 7968f26c9ffSDavid Dillow state->nfmr++; 7978f26c9ffSDavid Dillow 7988f26c9ffSDavid Dillow srp_map_desc(state, 0, state->fmr_len, fmr->fmr->rkey); 7998f26c9ffSDavid Dillow state->npages = state->fmr_len = 0; 8008f26c9ffSDavid Dillow return 0; 8018f26c9ffSDavid Dillow } 8028f26c9ffSDavid Dillow 8038f26c9ffSDavid Dillow static void srp_map_update_start(struct srp_map_state *state, 8048f26c9ffSDavid Dillow struct scatterlist *sg, int sg_index, 8058f26c9ffSDavid Dillow dma_addr_t dma_addr) 8068f26c9ffSDavid Dillow { 8078f26c9ffSDavid Dillow state->unmapped_sg = sg; 8088f26c9ffSDavid Dillow state->unmapped_index = sg_index; 8098f26c9ffSDavid Dillow state->unmapped_addr = dma_addr; 8108f26c9ffSDavid Dillow } 8118f26c9ffSDavid Dillow 8128f26c9ffSDavid Dillow static int srp_map_sg_entry(struct srp_map_state *state, 8138f26c9ffSDavid Dillow struct srp_target_port *target, 8148f26c9ffSDavid Dillow struct scatterlist *sg, int sg_index, 8158f26c9ffSDavid Dillow int use_fmr) 8168f26c9ffSDavid Dillow { 81705321937SGreg Kroah-Hartman struct srp_device *dev = target->srp_host->srp_dev; 81885507bccSRalph Campbell struct ib_device *ibdev = dev->dev; 8198f26c9ffSDavid Dillow dma_addr_t dma_addr = ib_sg_dma_address(ibdev, sg); 820bb350d1dSFUJITA Tomonori unsigned int dma_len = ib_sg_dma_len(ibdev, sg); 8218f26c9ffSDavid Dillow unsigned int len; 8228f26c9ffSDavid Dillow int ret; 82385507bccSRalph Campbell 8248f26c9ffSDavid Dillow if (!dma_len) 8258f26c9ffSDavid Dillow return 0; 8268f26c9ffSDavid Dillow 8278f26c9ffSDavid Dillow if (use_fmr == SRP_MAP_NO_FMR) { 8288f26c9ffSDavid Dillow /* Once we're in direct map mode for a request, we don't 8298f26c9ffSDavid Dillow * go back to FMR mode, so no need to update anything 8308f26c9ffSDavid Dillow * other than the descriptor. 8318f26c9ffSDavid Dillow */ 8328f26c9ffSDavid Dillow srp_map_desc(state, dma_addr, dma_len, target->rkey); 8338f26c9ffSDavid Dillow return 0; 834f5358a17SRoland Dreier } 835f5358a17SRoland Dreier 8368f26c9ffSDavid Dillow /* If we start at an offset into the FMR page, don't merge into 8378f26c9ffSDavid Dillow * the current FMR. Finish it out, and use the kernel's MR for this 8388f26c9ffSDavid Dillow * sg entry. This is to avoid potential bugs on some SRP targets 8398f26c9ffSDavid Dillow * that were never quite defined, but went away when the initiator 8408f26c9ffSDavid Dillow * avoided using FMR on such page fragments. 8418f26c9ffSDavid Dillow */ 8428f26c9ffSDavid Dillow if (dma_addr & ~dev->fmr_page_mask || dma_len > dev->fmr_max_size) { 8438f26c9ffSDavid Dillow ret = srp_map_finish_fmr(state, target); 8448f26c9ffSDavid Dillow if (ret) 8458f26c9ffSDavid Dillow return ret; 8468f26c9ffSDavid Dillow 8478f26c9ffSDavid Dillow srp_map_desc(state, dma_addr, dma_len, target->rkey); 8488f26c9ffSDavid Dillow srp_map_update_start(state, NULL, 0, 0); 8498f26c9ffSDavid Dillow return 0; 850f5358a17SRoland Dreier } 851f5358a17SRoland Dreier 8528f26c9ffSDavid Dillow /* If this is the first sg to go into the FMR, save our position. 8538f26c9ffSDavid Dillow * We need to know the first unmapped entry, its index, and the 8548f26c9ffSDavid Dillow * first unmapped address within that entry to be able to restart 8558f26c9ffSDavid Dillow * mapping after an error. 8568f26c9ffSDavid Dillow */ 8578f26c9ffSDavid Dillow if (!state->unmapped_sg) 8588f26c9ffSDavid Dillow srp_map_update_start(state, sg, sg_index, dma_addr); 859f5358a17SRoland Dreier 8608f26c9ffSDavid Dillow while (dma_len) { 8618f26c9ffSDavid Dillow if (state->npages == SRP_FMR_SIZE) { 8628f26c9ffSDavid Dillow ret = srp_map_finish_fmr(state, target); 8638f26c9ffSDavid Dillow if (ret) 8648f26c9ffSDavid Dillow return ret; 865f5358a17SRoland Dreier 8668f26c9ffSDavid Dillow srp_map_update_start(state, sg, sg_index, dma_addr); 86785507bccSRalph Campbell } 868f5358a17SRoland Dreier 8698f26c9ffSDavid Dillow len = min_t(unsigned int, dma_len, dev->fmr_page_size); 8708f26c9ffSDavid Dillow 8718f26c9ffSDavid Dillow if (!state->npages) 8728f26c9ffSDavid Dillow state->base_dma_addr = dma_addr; 8738f26c9ffSDavid Dillow state->pages[state->npages++] = dma_addr; 8748f26c9ffSDavid Dillow state->fmr_len += len; 8758f26c9ffSDavid Dillow dma_addr += len; 8768f26c9ffSDavid Dillow dma_len -= len; 877f5358a17SRoland Dreier } 878f5358a17SRoland Dreier 8798f26c9ffSDavid Dillow /* If the last entry of the FMR wasn't a full page, then we need to 8808f26c9ffSDavid Dillow * close it out and start a new one -- we can only merge at page 8818f26c9ffSDavid Dillow * boundries. 8828f26c9ffSDavid Dillow */ 883f5358a17SRoland Dreier ret = 0; 8848f26c9ffSDavid Dillow if (len != dev->fmr_page_size) { 8858f26c9ffSDavid Dillow ret = srp_map_finish_fmr(state, target); 8868f26c9ffSDavid Dillow if (!ret) 8878f26c9ffSDavid Dillow srp_map_update_start(state, NULL, 0, 0); 8888f26c9ffSDavid Dillow } 889f5358a17SRoland Dreier return ret; 890f5358a17SRoland Dreier } 891f5358a17SRoland Dreier 892aef9ec39SRoland Dreier static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target, 893aef9ec39SRoland Dreier struct srp_request *req) 894aef9ec39SRoland Dreier { 8958f26c9ffSDavid Dillow struct scatterlist *scat, *sg; 896aef9ec39SRoland Dreier struct srp_cmd *cmd = req->cmd->buf; 8978f26c9ffSDavid Dillow int i, len, nents, count, use_fmr; 89885507bccSRalph Campbell struct srp_device *dev; 89985507bccSRalph Campbell struct ib_device *ibdev; 9008f26c9ffSDavid Dillow struct srp_map_state state; 9018f26c9ffSDavid Dillow struct srp_indirect_buf *indirect_hdr; 9028f26c9ffSDavid Dillow u32 table_len; 9038f26c9ffSDavid Dillow u8 fmt; 904aef9ec39SRoland Dreier 905bb350d1dSFUJITA Tomonori if (!scsi_sglist(scmnd) || scmnd->sc_data_direction == DMA_NONE) 906aef9ec39SRoland Dreier return sizeof (struct srp_cmd); 907aef9ec39SRoland Dreier 908aef9ec39SRoland Dreier if (scmnd->sc_data_direction != DMA_FROM_DEVICE && 909aef9ec39SRoland Dreier scmnd->sc_data_direction != DMA_TO_DEVICE) { 9107aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 9117aa54bd7SDavid Dillow PFX "Unhandled data direction %d\n", 912aef9ec39SRoland Dreier scmnd->sc_data_direction); 913aef9ec39SRoland Dreier return -EINVAL; 914aef9ec39SRoland Dreier } 915aef9ec39SRoland Dreier 916bb350d1dSFUJITA Tomonori nents = scsi_sg_count(scmnd); 917bb350d1dSFUJITA Tomonori scat = scsi_sglist(scmnd); 918aef9ec39SRoland Dreier 91905321937SGreg Kroah-Hartman dev = target->srp_host->srp_dev; 92085507bccSRalph Campbell ibdev = dev->dev; 92185507bccSRalph Campbell 92285507bccSRalph Campbell count = ib_dma_map_sg(ibdev, scat, nents, scmnd->sc_data_direction); 9238f26c9ffSDavid Dillow if (unlikely(count == 0)) 9248f26c9ffSDavid Dillow return -EIO; 925aef9ec39SRoland Dreier 926aef9ec39SRoland Dreier fmt = SRP_DATA_DESC_DIRECT; 927f5358a17SRoland Dreier len = sizeof (struct srp_cmd) + sizeof (struct srp_direct_buf); 928f5358a17SRoland Dreier 929f5358a17SRoland Dreier if (count == 1) { 930f5358a17SRoland Dreier /* 931f5358a17SRoland Dreier * The midlayer only generated a single gather/scatter 932f5358a17SRoland Dreier * entry, or DMA mapping coalesced everything to a 933f5358a17SRoland Dreier * single entry. So a direct descriptor along with 934f5358a17SRoland Dreier * the DMA MR suffices. 935f5358a17SRoland Dreier */ 936f5358a17SRoland Dreier struct srp_direct_buf *buf = (void *) cmd->add_data; 937aef9ec39SRoland Dreier 93885507bccSRalph Campbell buf->va = cpu_to_be64(ib_sg_dma_address(ibdev, scat)); 9399af76271SDavid Dillow buf->key = cpu_to_be32(target->rkey); 94085507bccSRalph Campbell buf->len = cpu_to_be32(ib_sg_dma_len(ibdev, scat)); 9418f26c9ffSDavid Dillow 9428f26c9ffSDavid Dillow req->nfmr = 0; 9438f26c9ffSDavid Dillow goto map_complete; 9448f26c9ffSDavid Dillow } 9458f26c9ffSDavid Dillow 9468f26c9ffSDavid Dillow /* We have more than one scatter/gather entry, so build our indirect 9478f26c9ffSDavid Dillow * descriptor table, trying to merge as many entries with FMR as we 9488f26c9ffSDavid Dillow * can. 949f5358a17SRoland Dreier */ 9508f26c9ffSDavid Dillow indirect_hdr = (void *) cmd->add_data; 9518f26c9ffSDavid Dillow 952c07d424dSDavid Dillow ib_dma_sync_single_for_cpu(ibdev, req->indirect_dma_addr, 953c07d424dSDavid Dillow target->indirect_size, DMA_TO_DEVICE); 954c07d424dSDavid Dillow 9558f26c9ffSDavid Dillow memset(&state, 0, sizeof(state)); 956c07d424dSDavid Dillow state.desc = req->indirect_desc; 9578f26c9ffSDavid Dillow state.pages = req->map_page; 9588f26c9ffSDavid Dillow state.next_fmr = req->fmr_list; 9598f26c9ffSDavid Dillow 9608f26c9ffSDavid Dillow use_fmr = dev->fmr_pool ? SRP_MAP_ALLOW_FMR : SRP_MAP_NO_FMR; 9618f26c9ffSDavid Dillow 9628f26c9ffSDavid Dillow for_each_sg(scat, sg, count, i) { 9638f26c9ffSDavid Dillow if (srp_map_sg_entry(&state, target, sg, i, use_fmr)) { 9648f26c9ffSDavid Dillow /* FMR mapping failed, so backtrack to the first 9658f26c9ffSDavid Dillow * unmapped entry and continue on without using FMR. 9668f26c9ffSDavid Dillow */ 9678f26c9ffSDavid Dillow dma_addr_t dma_addr; 9688f26c9ffSDavid Dillow unsigned int dma_len; 9698f26c9ffSDavid Dillow 9708f26c9ffSDavid Dillow backtrack: 9718f26c9ffSDavid Dillow sg = state.unmapped_sg; 9728f26c9ffSDavid Dillow i = state.unmapped_index; 9738f26c9ffSDavid Dillow 9748f26c9ffSDavid Dillow dma_addr = ib_sg_dma_address(ibdev, sg); 9758f26c9ffSDavid Dillow dma_len = ib_sg_dma_len(ibdev, sg); 9768f26c9ffSDavid Dillow dma_len -= (state.unmapped_addr - dma_addr); 9778f26c9ffSDavid Dillow dma_addr = state.unmapped_addr; 9788f26c9ffSDavid Dillow use_fmr = SRP_MAP_NO_FMR; 9798f26c9ffSDavid Dillow srp_map_desc(&state, dma_addr, dma_len, target->rkey); 9808f26c9ffSDavid Dillow } 9818f26c9ffSDavid Dillow } 9828f26c9ffSDavid Dillow 9838f26c9ffSDavid Dillow if (use_fmr == SRP_MAP_ALLOW_FMR && srp_map_finish_fmr(&state, target)) 9848f26c9ffSDavid Dillow goto backtrack; 9858f26c9ffSDavid Dillow 986c07d424dSDavid Dillow /* We've mapped the request, now pull as much of the indirect 987c07d424dSDavid Dillow * descriptor table as we can into the command buffer. If this 988c07d424dSDavid Dillow * target is not using an external indirect table, we are 989c07d424dSDavid Dillow * guaranteed to fit into the command, as the SCSI layer won't 990c07d424dSDavid Dillow * give us more S/G entries than we allow. 9918f26c9ffSDavid Dillow */ 9928f26c9ffSDavid Dillow req->nfmr = state.nfmr; 9938f26c9ffSDavid Dillow if (state.ndesc == 1) { 9948f26c9ffSDavid Dillow /* FMR mapping was able to collapse this to one entry, 9958f26c9ffSDavid Dillow * so use a direct descriptor. 9968f26c9ffSDavid Dillow */ 9978f26c9ffSDavid Dillow struct srp_direct_buf *buf = (void *) cmd->add_data; 9988f26c9ffSDavid Dillow 999c07d424dSDavid Dillow *buf = req->indirect_desc[0]; 10008f26c9ffSDavid Dillow goto map_complete; 10018f26c9ffSDavid Dillow } 10028f26c9ffSDavid Dillow 1003c07d424dSDavid Dillow if (unlikely(target->cmd_sg_cnt < state.ndesc && 1004c07d424dSDavid Dillow !target->allow_ext_sg)) { 1005c07d424dSDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 1006c07d424dSDavid Dillow "Could not fit S/G list into SRP_CMD\n"); 1007c07d424dSDavid Dillow return -EIO; 1008c07d424dSDavid Dillow } 1009c07d424dSDavid Dillow 1010c07d424dSDavid Dillow count = min(state.ndesc, target->cmd_sg_cnt); 10118f26c9ffSDavid Dillow table_len = state.ndesc * sizeof (struct srp_direct_buf); 1012aef9ec39SRoland Dreier 1013aef9ec39SRoland Dreier fmt = SRP_DATA_DESC_INDIRECT; 10148f26c9ffSDavid Dillow len = sizeof(struct srp_cmd) + sizeof (struct srp_indirect_buf); 1015c07d424dSDavid Dillow len += count * sizeof (struct srp_direct_buf); 1016f5358a17SRoland Dreier 1017c07d424dSDavid Dillow memcpy(indirect_hdr->desc_list, req->indirect_desc, 1018c07d424dSDavid Dillow count * sizeof (struct srp_direct_buf)); 101985507bccSRalph Campbell 1020c07d424dSDavid Dillow indirect_hdr->table_desc.va = cpu_to_be64(req->indirect_dma_addr); 10218f26c9ffSDavid Dillow indirect_hdr->table_desc.key = cpu_to_be32(target->rkey); 10228f26c9ffSDavid Dillow indirect_hdr->table_desc.len = cpu_to_be32(table_len); 10238f26c9ffSDavid Dillow indirect_hdr->len = cpu_to_be32(state.total_len); 1024aef9ec39SRoland Dreier 1025aef9ec39SRoland Dreier if (scmnd->sc_data_direction == DMA_TO_DEVICE) 1026c07d424dSDavid Dillow cmd->data_out_desc_cnt = count; 1027aef9ec39SRoland Dreier else 1028c07d424dSDavid Dillow cmd->data_in_desc_cnt = count; 1029c07d424dSDavid Dillow 1030c07d424dSDavid Dillow ib_dma_sync_single_for_device(ibdev, req->indirect_dma_addr, table_len, 1031c07d424dSDavid Dillow DMA_TO_DEVICE); 1032aef9ec39SRoland Dreier 10338f26c9ffSDavid Dillow map_complete: 1034aef9ec39SRoland Dreier if (scmnd->sc_data_direction == DMA_TO_DEVICE) 1035aef9ec39SRoland Dreier cmd->buf_fmt = fmt << 4; 1036aef9ec39SRoland Dreier else 1037aef9ec39SRoland Dreier cmd->buf_fmt = fmt; 1038aef9ec39SRoland Dreier 1039aef9ec39SRoland Dreier return len; 1040aef9ec39SRoland Dreier } 1041aef9ec39SRoland Dreier 104205a1d750SDavid Dillow /* 104376c75b25SBart Van Assche * Return an IU and possible credit to the free pool 104476c75b25SBart Van Assche */ 104576c75b25SBart Van Assche static void srp_put_tx_iu(struct srp_target_port *target, struct srp_iu *iu, 104676c75b25SBart Van Assche enum srp_iu_type iu_type) 104776c75b25SBart Van Assche { 104876c75b25SBart Van Assche unsigned long flags; 104976c75b25SBart Van Assche 1050e9684678SBart Van Assche spin_lock_irqsave(&target->lock, flags); 105176c75b25SBart Van Assche list_add(&iu->list, &target->free_tx); 105276c75b25SBart Van Assche if (iu_type != SRP_IU_RSP) 105376c75b25SBart Van Assche ++target->req_lim; 1054e9684678SBart Van Assche spin_unlock_irqrestore(&target->lock, flags); 105576c75b25SBart Van Assche } 105676c75b25SBart Van Assche 105776c75b25SBart Van Assche /* 1058e9684678SBart Van Assche * Must be called with target->lock held to protect req_lim and free_tx. 1059e9684678SBart Van Assche * If IU is not sent, it must be returned using srp_put_tx_iu(). 106005a1d750SDavid Dillow * 106105a1d750SDavid Dillow * Note: 106205a1d750SDavid Dillow * An upper limit for the number of allocated information units for each 106305a1d750SDavid Dillow * request type is: 106405a1d750SDavid Dillow * - SRP_IU_CMD: SRP_CMD_SQ_SIZE, since the SCSI mid-layer never queues 106505a1d750SDavid Dillow * more than Scsi_Host.can_queue requests. 106605a1d750SDavid Dillow * - SRP_IU_TSK_MGMT: SRP_TSK_MGMT_SQ_SIZE. 106705a1d750SDavid Dillow * - SRP_IU_RSP: 1, since a conforming SRP target never sends more than 106805a1d750SDavid Dillow * one unanswered SRP request to an initiator. 106905a1d750SDavid Dillow */ 107005a1d750SDavid Dillow static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target, 107105a1d750SDavid Dillow enum srp_iu_type iu_type) 107205a1d750SDavid Dillow { 107305a1d750SDavid Dillow s32 rsv = (iu_type == SRP_IU_TSK_MGMT) ? 0 : SRP_TSK_MGMT_SQ_SIZE; 107405a1d750SDavid Dillow struct srp_iu *iu; 107505a1d750SDavid Dillow 107605a1d750SDavid Dillow srp_send_completion(target->send_cq, target); 107705a1d750SDavid Dillow 1078dcb4cb85SBart Van Assche if (list_empty(&target->free_tx)) 107905a1d750SDavid Dillow return NULL; 108005a1d750SDavid Dillow 108105a1d750SDavid Dillow /* Initiator responses to target requests do not consume credits */ 108276c75b25SBart Van Assche if (iu_type != SRP_IU_RSP) { 108376c75b25SBart Van Assche if (target->req_lim <= rsv) { 108405a1d750SDavid Dillow ++target->zero_req_lim; 108505a1d750SDavid Dillow return NULL; 108605a1d750SDavid Dillow } 108705a1d750SDavid Dillow 108876c75b25SBart Van Assche --target->req_lim; 108976c75b25SBart Van Assche } 109076c75b25SBart Van Assche 1091dcb4cb85SBart Van Assche iu = list_first_entry(&target->free_tx, struct srp_iu, list); 109276c75b25SBart Van Assche list_del(&iu->list); 109305a1d750SDavid Dillow return iu; 109405a1d750SDavid Dillow } 109505a1d750SDavid Dillow 109676c75b25SBart Van Assche static int srp_post_send(struct srp_target_port *target, 109705a1d750SDavid Dillow struct srp_iu *iu, int len) 109805a1d750SDavid Dillow { 109905a1d750SDavid Dillow struct ib_sge list; 110005a1d750SDavid Dillow struct ib_send_wr wr, *bad_wr; 110105a1d750SDavid Dillow 110205a1d750SDavid Dillow list.addr = iu->dma; 110305a1d750SDavid Dillow list.length = len; 11049af76271SDavid Dillow list.lkey = target->lkey; 110505a1d750SDavid Dillow 110605a1d750SDavid Dillow wr.next = NULL; 1107dcb4cb85SBart Van Assche wr.wr_id = (uintptr_t) iu; 110805a1d750SDavid Dillow wr.sg_list = &list; 110905a1d750SDavid Dillow wr.num_sge = 1; 111005a1d750SDavid Dillow wr.opcode = IB_WR_SEND; 111105a1d750SDavid Dillow wr.send_flags = IB_SEND_SIGNALED; 111205a1d750SDavid Dillow 111376c75b25SBart Van Assche return ib_post_send(target->qp, &wr, &bad_wr); 111405a1d750SDavid Dillow } 111505a1d750SDavid Dillow 1116dcb4cb85SBart Van Assche static int srp_post_recv(struct srp_target_port *target, struct srp_iu *iu) 1117c996bb47SBart Van Assche { 1118c996bb47SBart Van Assche struct ib_recv_wr wr, *bad_wr; 1119dcb4cb85SBart Van Assche struct ib_sge list; 1120c996bb47SBart Van Assche 1121c996bb47SBart Van Assche list.addr = iu->dma; 1122c996bb47SBart Van Assche list.length = iu->size; 11239af76271SDavid Dillow list.lkey = target->lkey; 1124c996bb47SBart Van Assche 1125c996bb47SBart Van Assche wr.next = NULL; 1126dcb4cb85SBart Van Assche wr.wr_id = (uintptr_t) iu; 1127c996bb47SBart Van Assche wr.sg_list = &list; 1128c996bb47SBart Van Assche wr.num_sge = 1; 1129c996bb47SBart Van Assche 1130dcb4cb85SBart Van Assche return ib_post_recv(target->qp, &wr, &bad_wr); 1131c996bb47SBart Van Assche } 1132c996bb47SBart Van Assche 1133aef9ec39SRoland Dreier static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) 1134aef9ec39SRoland Dreier { 1135aef9ec39SRoland Dreier struct srp_request *req; 1136aef9ec39SRoland Dreier struct scsi_cmnd *scmnd; 1137aef9ec39SRoland Dreier unsigned long flags; 1138aef9ec39SRoland Dreier 1139aef9ec39SRoland Dreier if (unlikely(rsp->tag & SRP_TAG_TSK_MGMT)) { 1140e9684678SBart Van Assche spin_lock_irqsave(&target->lock, flags); 114194a9174cSBart Van Assche target->req_lim += be32_to_cpu(rsp->req_lim_delta); 1142e9684678SBart Van Assche spin_unlock_irqrestore(&target->lock, flags); 114394a9174cSBart Van Assche 1144f8b6e31eSDavid Dillow target->tsk_mgmt_status = -1; 1145f8b6e31eSDavid Dillow if (be32_to_cpu(rsp->resp_data_len) >= 4) 1146f8b6e31eSDavid Dillow target->tsk_mgmt_status = rsp->data[3]; 1147f8b6e31eSDavid Dillow complete(&target->tsk_mgmt_done); 1148aef9ec39SRoland Dreier } else { 1149f8b6e31eSDavid Dillow req = &target->req_ring[rsp->tag]; 115022032991SBart Van Assche scmnd = srp_claim_req(target, req, NULL); 115122032991SBart Van Assche if (!scmnd) { 11527aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 11537aa54bd7SDavid Dillow "Null scmnd for RSP w/tag %016llx\n", 1154aef9ec39SRoland Dreier (unsigned long long) rsp->tag); 115522032991SBart Van Assche 115622032991SBart Van Assche spin_lock_irqsave(&target->lock, flags); 115722032991SBart Van Assche target->req_lim += be32_to_cpu(rsp->req_lim_delta); 115822032991SBart Van Assche spin_unlock_irqrestore(&target->lock, flags); 115922032991SBart Van Assche 116022032991SBart Van Assche return; 116122032991SBart Van Assche } 1162aef9ec39SRoland Dreier scmnd->result = rsp->status; 1163aef9ec39SRoland Dreier 1164aef9ec39SRoland Dreier if (rsp->flags & SRP_RSP_FLAG_SNSVALID) { 1165aef9ec39SRoland Dreier memcpy(scmnd->sense_buffer, rsp->data + 1166aef9ec39SRoland Dreier be32_to_cpu(rsp->resp_data_len), 1167aef9ec39SRoland Dreier min_t(int, be32_to_cpu(rsp->sense_data_len), 1168aef9ec39SRoland Dreier SCSI_SENSE_BUFFERSIZE)); 1169aef9ec39SRoland Dreier } 1170aef9ec39SRoland Dreier 1171aef9ec39SRoland Dreier if (rsp->flags & (SRP_RSP_FLAG_DOOVER | SRP_RSP_FLAG_DOUNDER)) 1172bb350d1dSFUJITA Tomonori scsi_set_resid(scmnd, be32_to_cpu(rsp->data_out_res_cnt)); 1173aef9ec39SRoland Dreier else if (rsp->flags & (SRP_RSP_FLAG_DIOVER | SRP_RSP_FLAG_DIUNDER)) 1174bb350d1dSFUJITA Tomonori scsi_set_resid(scmnd, be32_to_cpu(rsp->data_in_res_cnt)); 1175aef9ec39SRoland Dreier 117622032991SBart Van Assche srp_free_req(target, req, scmnd, 117722032991SBart Van Assche be32_to_cpu(rsp->req_lim_delta)); 117822032991SBart Van Assche 1179f8b6e31eSDavid Dillow scmnd->host_scribble = NULL; 1180aef9ec39SRoland Dreier scmnd->scsi_done(scmnd); 1181aef9ec39SRoland Dreier } 1182aef9ec39SRoland Dreier } 1183aef9ec39SRoland Dreier 1184bb12588aSDavid Dillow static int srp_response_common(struct srp_target_port *target, s32 req_delta, 1185bb12588aSDavid Dillow void *rsp, int len) 1186bb12588aSDavid Dillow { 118776c75b25SBart Van Assche struct ib_device *dev = target->srp_host->srp_dev->dev; 1188bb12588aSDavid Dillow unsigned long flags; 1189bb12588aSDavid Dillow struct srp_iu *iu; 119076c75b25SBart Van Assche int err; 1191bb12588aSDavid Dillow 1192e9684678SBart Van Assche spin_lock_irqsave(&target->lock, flags); 1193bb12588aSDavid Dillow target->req_lim += req_delta; 1194bb12588aSDavid Dillow iu = __srp_get_tx_iu(target, SRP_IU_RSP); 1195e9684678SBart Van Assche spin_unlock_irqrestore(&target->lock, flags); 119676c75b25SBart Van Assche 1197bb12588aSDavid Dillow if (!iu) { 1198bb12588aSDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX 1199bb12588aSDavid Dillow "no IU available to send response\n"); 120076c75b25SBart Van Assche return 1; 1201bb12588aSDavid Dillow } 1202bb12588aSDavid Dillow 1203bb12588aSDavid Dillow ib_dma_sync_single_for_cpu(dev, iu->dma, len, DMA_TO_DEVICE); 1204bb12588aSDavid Dillow memcpy(iu->buf, rsp, len); 1205bb12588aSDavid Dillow ib_dma_sync_single_for_device(dev, iu->dma, len, DMA_TO_DEVICE); 1206bb12588aSDavid Dillow 120776c75b25SBart Van Assche err = srp_post_send(target, iu, len); 120876c75b25SBart Van Assche if (err) { 1209bb12588aSDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX 1210bb12588aSDavid Dillow "unable to post response: %d\n", err); 121176c75b25SBart Van Assche srp_put_tx_iu(target, iu, SRP_IU_RSP); 121276c75b25SBart Van Assche } 1213bb12588aSDavid Dillow 1214bb12588aSDavid Dillow return err; 1215bb12588aSDavid Dillow } 1216bb12588aSDavid Dillow 1217bb12588aSDavid Dillow static void srp_process_cred_req(struct srp_target_port *target, 1218bb12588aSDavid Dillow struct srp_cred_req *req) 1219bb12588aSDavid Dillow { 1220bb12588aSDavid Dillow struct srp_cred_rsp rsp = { 1221bb12588aSDavid Dillow .opcode = SRP_CRED_RSP, 1222bb12588aSDavid Dillow .tag = req->tag, 1223bb12588aSDavid Dillow }; 1224bb12588aSDavid Dillow s32 delta = be32_to_cpu(req->req_lim_delta); 1225bb12588aSDavid Dillow 1226bb12588aSDavid Dillow if (srp_response_common(target, delta, &rsp, sizeof rsp)) 1227bb12588aSDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX 1228bb12588aSDavid Dillow "problems processing SRP_CRED_REQ\n"); 1229bb12588aSDavid Dillow } 1230bb12588aSDavid Dillow 1231bb12588aSDavid Dillow static void srp_process_aer_req(struct srp_target_port *target, 1232bb12588aSDavid Dillow struct srp_aer_req *req) 1233bb12588aSDavid Dillow { 1234bb12588aSDavid Dillow struct srp_aer_rsp rsp = { 1235bb12588aSDavid Dillow .opcode = SRP_AER_RSP, 1236bb12588aSDavid Dillow .tag = req->tag, 1237bb12588aSDavid Dillow }; 1238bb12588aSDavid Dillow s32 delta = be32_to_cpu(req->req_lim_delta); 1239bb12588aSDavid Dillow 1240bb12588aSDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX 1241bb12588aSDavid Dillow "ignoring AER for LUN %llu\n", be64_to_cpu(req->lun)); 1242bb12588aSDavid Dillow 1243bb12588aSDavid Dillow if (srp_response_common(target, delta, &rsp, sizeof rsp)) 1244bb12588aSDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX 1245bb12588aSDavid Dillow "problems processing SRP_AER_REQ\n"); 1246bb12588aSDavid Dillow } 1247bb12588aSDavid Dillow 1248aef9ec39SRoland Dreier static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc) 1249aef9ec39SRoland Dreier { 1250dcb4cb85SBart Van Assche struct ib_device *dev = target->srp_host->srp_dev->dev; 1251737b94ebSRoland Dreier struct srp_iu *iu = (struct srp_iu *) (uintptr_t) wc->wr_id; 1252c996bb47SBart Van Assche int res; 1253aef9ec39SRoland Dreier u8 opcode; 1254aef9ec39SRoland Dreier 125585507bccSRalph Campbell ib_dma_sync_single_for_cpu(dev, iu->dma, target->max_ti_iu_len, 125685507bccSRalph Campbell DMA_FROM_DEVICE); 1257aef9ec39SRoland Dreier 1258aef9ec39SRoland Dreier opcode = *(u8 *) iu->buf; 1259aef9ec39SRoland Dreier 1260aef9ec39SRoland Dreier if (0) { 12617aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 12627aa54bd7SDavid Dillow PFX "recv completion, opcode 0x%02x\n", opcode); 12637a700811SBart Van Assche print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 8, 1, 12647a700811SBart Van Assche iu->buf, wc->byte_len, true); 1265aef9ec39SRoland Dreier } 1266aef9ec39SRoland Dreier 1267aef9ec39SRoland Dreier switch (opcode) { 1268aef9ec39SRoland Dreier case SRP_RSP: 1269aef9ec39SRoland Dreier srp_process_rsp(target, iu->buf); 1270aef9ec39SRoland Dreier break; 1271aef9ec39SRoland Dreier 1272bb12588aSDavid Dillow case SRP_CRED_REQ: 1273bb12588aSDavid Dillow srp_process_cred_req(target, iu->buf); 1274bb12588aSDavid Dillow break; 1275bb12588aSDavid Dillow 1276bb12588aSDavid Dillow case SRP_AER_REQ: 1277bb12588aSDavid Dillow srp_process_aer_req(target, iu->buf); 1278bb12588aSDavid Dillow break; 1279bb12588aSDavid Dillow 1280aef9ec39SRoland Dreier case SRP_T_LOGOUT: 1281aef9ec39SRoland Dreier /* XXX Handle target logout */ 12827aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 12837aa54bd7SDavid Dillow PFX "Got target logout request\n"); 1284aef9ec39SRoland Dreier break; 1285aef9ec39SRoland Dreier 1286aef9ec39SRoland Dreier default: 12877aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 12887aa54bd7SDavid Dillow PFX "Unhandled SRP opcode 0x%02x\n", opcode); 1289aef9ec39SRoland Dreier break; 1290aef9ec39SRoland Dreier } 1291aef9ec39SRoland Dreier 129285507bccSRalph Campbell ib_dma_sync_single_for_device(dev, iu->dma, target->max_ti_iu_len, 129385507bccSRalph Campbell DMA_FROM_DEVICE); 1294c996bb47SBart Van Assche 1295dcb4cb85SBart Van Assche res = srp_post_recv(target, iu); 1296c996bb47SBart Van Assche if (res != 0) 1297c996bb47SBart Van Assche shost_printk(KERN_ERR, target->scsi_host, 1298c996bb47SBart Van Assche PFX "Recv failed with error code %d\n", res); 1299aef9ec39SRoland Dreier } 1300aef9ec39SRoland Dreier 1301948d1e88SBart Van Assche static void srp_handle_qp_err(enum ib_wc_status wc_status, 1302948d1e88SBart Van Assche enum ib_wc_opcode wc_opcode, 1303948d1e88SBart Van Assche struct srp_target_port *target) 1304948d1e88SBart Van Assche { 1305294c875aSBart Van Assche if (target->connected && !target->qp_in_error) { 13064f0af697SBart Van Assche shost_printk(KERN_ERR, target->scsi_host, 13074f0af697SBart Van Assche PFX "failed %s status %d\n", 13084f0af697SBart Van Assche wc_opcode & IB_WC_RECV ? "receive" : "send", 13094f0af697SBart Van Assche wc_status); 13104f0af697SBart Van Assche } 1311948d1e88SBart Van Assche target->qp_in_error = true; 1312948d1e88SBart Van Assche } 1313948d1e88SBart Van Assche 13149c03dc9fSBart Van Assche static void srp_recv_completion(struct ib_cq *cq, void *target_ptr) 1315aef9ec39SRoland Dreier { 1316aef9ec39SRoland Dreier struct srp_target_port *target = target_ptr; 1317aef9ec39SRoland Dreier struct ib_wc wc; 1318aef9ec39SRoland Dreier 1319aef9ec39SRoland Dreier ib_req_notify_cq(cq, IB_CQ_NEXT_COMP); 1320aef9ec39SRoland Dreier while (ib_poll_cq(cq, 1, &wc) > 0) { 1321948d1e88SBart Van Assche if (likely(wc.status == IB_WC_SUCCESS)) { 1322948d1e88SBart Van Assche srp_handle_recv(target, &wc); 1323948d1e88SBart Van Assche } else { 1324948d1e88SBart Van Assche srp_handle_qp_err(wc.status, wc.opcode, target); 1325aef9ec39SRoland Dreier } 13269c03dc9fSBart Van Assche } 13279c03dc9fSBart Van Assche } 13289c03dc9fSBart Van Assche 13299c03dc9fSBart Van Assche static void srp_send_completion(struct ib_cq *cq, void *target_ptr) 13309c03dc9fSBart Van Assche { 13319c03dc9fSBart Van Assche struct srp_target_port *target = target_ptr; 13329c03dc9fSBart Van Assche struct ib_wc wc; 1333dcb4cb85SBart Van Assche struct srp_iu *iu; 13349c03dc9fSBart Van Assche 13359c03dc9fSBart Van Assche while (ib_poll_cq(cq, 1, &wc) > 0) { 1336948d1e88SBart Van Assche if (likely(wc.status == IB_WC_SUCCESS)) { 1337737b94ebSRoland Dreier iu = (struct srp_iu *) (uintptr_t) wc.wr_id; 1338dcb4cb85SBart Van Assche list_add(&iu->list, &target->free_tx); 1339948d1e88SBart Van Assche } else { 1340948d1e88SBart Van Assche srp_handle_qp_err(wc.status, wc.opcode, target); 1341948d1e88SBart Van Assche } 1342aef9ec39SRoland Dreier } 1343aef9ec39SRoland Dreier } 1344aef9ec39SRoland Dreier 134576c75b25SBart Van Assche static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd) 1346aef9ec39SRoland Dreier { 134776c75b25SBart Van Assche struct srp_target_port *target = host_to_target(shost); 1348aef9ec39SRoland Dreier struct srp_request *req; 1349aef9ec39SRoland Dreier struct srp_iu *iu; 1350aef9ec39SRoland Dreier struct srp_cmd *cmd; 135185507bccSRalph Campbell struct ib_device *dev; 135276c75b25SBart Van Assche unsigned long flags; 1353aef9ec39SRoland Dreier int len; 1354aef9ec39SRoland Dreier 1355e9684678SBart Van Assche spin_lock_irqsave(&target->lock, flags); 1356bb12588aSDavid Dillow iu = __srp_get_tx_iu(target, SRP_IU_CMD); 1357aef9ec39SRoland Dreier if (!iu) 1358695b8349SBart Van Assche goto err_unlock; 1359695b8349SBart Van Assche 1360695b8349SBart Van Assche req = list_first_entry(&target->free_reqs, struct srp_request, list); 1361695b8349SBart Van Assche list_del(&req->list); 1362695b8349SBart Van Assche spin_unlock_irqrestore(&target->lock, flags); 1363aef9ec39SRoland Dreier 136405321937SGreg Kroah-Hartman dev = target->srp_host->srp_dev->dev; 136549248644SDavid Dillow ib_dma_sync_single_for_cpu(dev, iu->dma, target->max_iu_len, 136685507bccSRalph Campbell DMA_TO_DEVICE); 1367aef9ec39SRoland Dreier 1368aef9ec39SRoland Dreier scmnd->result = 0; 1369f8b6e31eSDavid Dillow scmnd->host_scribble = (void *) req; 1370aef9ec39SRoland Dreier 1371aef9ec39SRoland Dreier cmd = iu->buf; 1372aef9ec39SRoland Dreier memset(cmd, 0, sizeof *cmd); 1373aef9ec39SRoland Dreier 1374aef9ec39SRoland Dreier cmd->opcode = SRP_CMD; 1375aef9ec39SRoland Dreier cmd->lun = cpu_to_be64((u64) scmnd->device->lun << 48); 1376d945e1dfSRoland Dreier cmd->tag = req->index; 1377aef9ec39SRoland Dreier memcpy(cmd->cdb, scmnd->cmnd, scmnd->cmd_len); 1378aef9ec39SRoland Dreier 1379aef9ec39SRoland Dreier req->scmnd = scmnd; 1380aef9ec39SRoland Dreier req->cmd = iu; 1381aef9ec39SRoland Dreier 1382aef9ec39SRoland Dreier len = srp_map_data(scmnd, target, req); 1383aef9ec39SRoland Dreier if (len < 0) { 13847aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 13857aa54bd7SDavid Dillow PFX "Failed to map data\n"); 138676c75b25SBart Van Assche goto err_iu; 1387aef9ec39SRoland Dreier } 1388aef9ec39SRoland Dreier 138949248644SDavid Dillow ib_dma_sync_single_for_device(dev, iu->dma, target->max_iu_len, 139085507bccSRalph Campbell DMA_TO_DEVICE); 1391aef9ec39SRoland Dreier 139276c75b25SBart Van Assche if (srp_post_send(target, iu, len)) { 13937aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX "Send failed\n"); 1394aef9ec39SRoland Dreier goto err_unmap; 1395aef9ec39SRoland Dreier } 1396aef9ec39SRoland Dreier 1397aef9ec39SRoland Dreier return 0; 1398aef9ec39SRoland Dreier 1399aef9ec39SRoland Dreier err_unmap: 1400aef9ec39SRoland Dreier srp_unmap_data(scmnd, target, req); 1401aef9ec39SRoland Dreier 140276c75b25SBart Van Assche err_iu: 140376c75b25SBart Van Assche srp_put_tx_iu(target, iu, SRP_IU_CMD); 140476c75b25SBart Van Assche 1405e9684678SBart Van Assche spin_lock_irqsave(&target->lock, flags); 140676c75b25SBart Van Assche list_add(&req->list, &target->free_reqs); 1407695b8349SBart Van Assche 1408695b8349SBart Van Assche err_unlock: 1409e9684678SBart Van Assche spin_unlock_irqrestore(&target->lock, flags); 141076c75b25SBart Van Assche 1411aef9ec39SRoland Dreier return SCSI_MLQUEUE_HOST_BUSY; 1412aef9ec39SRoland Dreier } 1413aef9ec39SRoland Dreier 1414aef9ec39SRoland Dreier static int srp_alloc_iu_bufs(struct srp_target_port *target) 1415aef9ec39SRoland Dreier { 1416aef9ec39SRoland Dreier int i; 1417aef9ec39SRoland Dreier 1418aef9ec39SRoland Dreier for (i = 0; i < SRP_RQ_SIZE; ++i) { 1419aef9ec39SRoland Dreier target->rx_ring[i] = srp_alloc_iu(target->srp_host, 1420aef9ec39SRoland Dreier target->max_ti_iu_len, 1421aef9ec39SRoland Dreier GFP_KERNEL, DMA_FROM_DEVICE); 1422aef9ec39SRoland Dreier if (!target->rx_ring[i]) 1423aef9ec39SRoland Dreier goto err; 1424aef9ec39SRoland Dreier } 1425aef9ec39SRoland Dreier 1426dd5e6e38SBart Van Assche for (i = 0; i < SRP_SQ_SIZE; ++i) { 1427aef9ec39SRoland Dreier target->tx_ring[i] = srp_alloc_iu(target->srp_host, 142849248644SDavid Dillow target->max_iu_len, 1429aef9ec39SRoland Dreier GFP_KERNEL, DMA_TO_DEVICE); 1430aef9ec39SRoland Dreier if (!target->tx_ring[i]) 1431aef9ec39SRoland Dreier goto err; 1432dcb4cb85SBart Van Assche 1433dcb4cb85SBart Van Assche list_add(&target->tx_ring[i]->list, &target->free_tx); 1434aef9ec39SRoland Dreier } 1435aef9ec39SRoland Dreier 1436aef9ec39SRoland Dreier return 0; 1437aef9ec39SRoland Dreier 1438aef9ec39SRoland Dreier err: 1439aef9ec39SRoland Dreier for (i = 0; i < SRP_RQ_SIZE; ++i) { 1440aef9ec39SRoland Dreier srp_free_iu(target->srp_host, target->rx_ring[i]); 1441aef9ec39SRoland Dreier target->rx_ring[i] = NULL; 1442aef9ec39SRoland Dreier } 1443aef9ec39SRoland Dreier 1444dd5e6e38SBart Van Assche for (i = 0; i < SRP_SQ_SIZE; ++i) { 1445aef9ec39SRoland Dreier srp_free_iu(target->srp_host, target->tx_ring[i]); 1446aef9ec39SRoland Dreier target->tx_ring[i] = NULL; 1447aef9ec39SRoland Dreier } 1448aef9ec39SRoland Dreier 1449aef9ec39SRoland Dreier return -ENOMEM; 1450aef9ec39SRoland Dreier } 1451aef9ec39SRoland Dreier 1452c9b03c1aSBart Van Assche static uint32_t srp_compute_rq_tmo(struct ib_qp_attr *qp_attr, int attr_mask) 1453c9b03c1aSBart Van Assche { 1454c9b03c1aSBart Van Assche uint64_t T_tr_ns, max_compl_time_ms; 1455c9b03c1aSBart Van Assche uint32_t rq_tmo_jiffies; 1456c9b03c1aSBart Van Assche 1457c9b03c1aSBart Van Assche /* 1458c9b03c1aSBart Van Assche * According to section 11.2.4.2 in the IBTA spec (Modify Queue Pair, 1459c9b03c1aSBart Van Assche * table 91), both the QP timeout and the retry count have to be set 1460c9b03c1aSBart Van Assche * for RC QP's during the RTR to RTS transition. 1461c9b03c1aSBart Van Assche */ 1462c9b03c1aSBart Van Assche WARN_ON_ONCE((attr_mask & (IB_QP_TIMEOUT | IB_QP_RETRY_CNT)) != 1463c9b03c1aSBart Van Assche (IB_QP_TIMEOUT | IB_QP_RETRY_CNT)); 1464c9b03c1aSBart Van Assche 1465c9b03c1aSBart Van Assche /* 1466c9b03c1aSBart Van Assche * Set target->rq_tmo_jiffies to one second more than the largest time 1467c9b03c1aSBart Van Assche * it can take before an error completion is generated. See also 1468c9b03c1aSBart Van Assche * C9-140..142 in the IBTA spec for more information about how to 1469c9b03c1aSBart Van Assche * convert the QP Local ACK Timeout value to nanoseconds. 1470c9b03c1aSBart Van Assche */ 1471c9b03c1aSBart Van Assche T_tr_ns = 4096 * (1ULL << qp_attr->timeout); 1472c9b03c1aSBart Van Assche max_compl_time_ms = qp_attr->retry_cnt * 4 * T_tr_ns; 1473c9b03c1aSBart Van Assche do_div(max_compl_time_ms, NSEC_PER_MSEC); 1474c9b03c1aSBart Van Assche rq_tmo_jiffies = msecs_to_jiffies(max_compl_time_ms + 1000); 1475c9b03c1aSBart Van Assche 1476c9b03c1aSBart Van Assche return rq_tmo_jiffies; 1477c9b03c1aSBart Van Assche } 1478c9b03c1aSBart Van Assche 1479961e0be8SDavid Dillow static void srp_cm_rep_handler(struct ib_cm_id *cm_id, 1480961e0be8SDavid Dillow struct srp_login_rsp *lrsp, 1481961e0be8SDavid Dillow struct srp_target_port *target) 1482961e0be8SDavid Dillow { 1483961e0be8SDavid Dillow struct ib_qp_attr *qp_attr = NULL; 1484961e0be8SDavid Dillow int attr_mask = 0; 1485961e0be8SDavid Dillow int ret; 1486961e0be8SDavid Dillow int i; 1487961e0be8SDavid Dillow 1488961e0be8SDavid Dillow if (lrsp->opcode == SRP_LOGIN_RSP) { 1489961e0be8SDavid Dillow target->max_ti_iu_len = be32_to_cpu(lrsp->max_ti_iu_len); 1490961e0be8SDavid Dillow target->req_lim = be32_to_cpu(lrsp->req_lim_delta); 1491961e0be8SDavid Dillow 1492961e0be8SDavid Dillow /* 1493961e0be8SDavid Dillow * Reserve credits for task management so we don't 1494961e0be8SDavid Dillow * bounce requests back to the SCSI mid-layer. 1495961e0be8SDavid Dillow */ 1496961e0be8SDavid Dillow target->scsi_host->can_queue 1497961e0be8SDavid Dillow = min(target->req_lim - SRP_TSK_MGMT_SQ_SIZE, 1498961e0be8SDavid Dillow target->scsi_host->can_queue); 1499961e0be8SDavid Dillow } else { 1500961e0be8SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 1501961e0be8SDavid Dillow PFX "Unhandled RSP opcode %#x\n", lrsp->opcode); 1502961e0be8SDavid Dillow ret = -ECONNRESET; 1503961e0be8SDavid Dillow goto error; 1504961e0be8SDavid Dillow } 1505961e0be8SDavid Dillow 1506961e0be8SDavid Dillow if (!target->rx_ring[0]) { 1507961e0be8SDavid Dillow ret = srp_alloc_iu_bufs(target); 1508961e0be8SDavid Dillow if (ret) 1509961e0be8SDavid Dillow goto error; 1510961e0be8SDavid Dillow } 1511961e0be8SDavid Dillow 1512961e0be8SDavid Dillow ret = -ENOMEM; 1513961e0be8SDavid Dillow qp_attr = kmalloc(sizeof *qp_attr, GFP_KERNEL); 1514961e0be8SDavid Dillow if (!qp_attr) 1515961e0be8SDavid Dillow goto error; 1516961e0be8SDavid Dillow 1517961e0be8SDavid Dillow qp_attr->qp_state = IB_QPS_RTR; 1518961e0be8SDavid Dillow ret = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask); 1519961e0be8SDavid Dillow if (ret) 1520961e0be8SDavid Dillow goto error_free; 1521961e0be8SDavid Dillow 1522961e0be8SDavid Dillow ret = ib_modify_qp(target->qp, qp_attr, attr_mask); 1523961e0be8SDavid Dillow if (ret) 1524961e0be8SDavid Dillow goto error_free; 1525961e0be8SDavid Dillow 1526961e0be8SDavid Dillow for (i = 0; i < SRP_RQ_SIZE; i++) { 1527961e0be8SDavid Dillow struct srp_iu *iu = target->rx_ring[i]; 1528961e0be8SDavid Dillow ret = srp_post_recv(target, iu); 1529961e0be8SDavid Dillow if (ret) 1530961e0be8SDavid Dillow goto error_free; 1531961e0be8SDavid Dillow } 1532961e0be8SDavid Dillow 1533961e0be8SDavid Dillow qp_attr->qp_state = IB_QPS_RTS; 1534961e0be8SDavid Dillow ret = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask); 1535961e0be8SDavid Dillow if (ret) 1536961e0be8SDavid Dillow goto error_free; 1537961e0be8SDavid Dillow 1538c9b03c1aSBart Van Assche target->rq_tmo_jiffies = srp_compute_rq_tmo(qp_attr, attr_mask); 1539c9b03c1aSBart Van Assche 1540961e0be8SDavid Dillow ret = ib_modify_qp(target->qp, qp_attr, attr_mask); 1541961e0be8SDavid Dillow if (ret) 1542961e0be8SDavid Dillow goto error_free; 1543961e0be8SDavid Dillow 1544961e0be8SDavid Dillow ret = ib_send_cm_rtu(cm_id, NULL, 0); 1545961e0be8SDavid Dillow 1546961e0be8SDavid Dillow error_free: 1547961e0be8SDavid Dillow kfree(qp_attr); 1548961e0be8SDavid Dillow 1549961e0be8SDavid Dillow error: 1550961e0be8SDavid Dillow target->status = ret; 1551961e0be8SDavid Dillow } 1552961e0be8SDavid Dillow 1553aef9ec39SRoland Dreier static void srp_cm_rej_handler(struct ib_cm_id *cm_id, 1554aef9ec39SRoland Dreier struct ib_cm_event *event, 1555aef9ec39SRoland Dreier struct srp_target_port *target) 1556aef9ec39SRoland Dreier { 15577aa54bd7SDavid Dillow struct Scsi_Host *shost = target->scsi_host; 1558aef9ec39SRoland Dreier struct ib_class_port_info *cpi; 1559aef9ec39SRoland Dreier int opcode; 1560aef9ec39SRoland Dreier 1561aef9ec39SRoland Dreier switch (event->param.rej_rcvd.reason) { 1562aef9ec39SRoland Dreier case IB_CM_REJ_PORT_CM_REDIRECT: 1563aef9ec39SRoland Dreier cpi = event->param.rej_rcvd.ari; 1564aef9ec39SRoland Dreier target->path.dlid = cpi->redirect_lid; 1565aef9ec39SRoland Dreier target->path.pkey = cpi->redirect_pkey; 1566aef9ec39SRoland Dreier cm_id->remote_cm_qpn = be32_to_cpu(cpi->redirect_qp) & 0x00ffffff; 1567aef9ec39SRoland Dreier memcpy(target->path.dgid.raw, cpi->redirect_gid, 16); 1568aef9ec39SRoland Dreier 1569aef9ec39SRoland Dreier target->status = target->path.dlid ? 1570aef9ec39SRoland Dreier SRP_DLID_REDIRECT : SRP_PORT_REDIRECT; 1571aef9ec39SRoland Dreier break; 1572aef9ec39SRoland Dreier 1573aef9ec39SRoland Dreier case IB_CM_REJ_PORT_REDIRECT: 15745d7cbfd6SRoland Dreier if (srp_target_is_topspin(target)) { 1575aef9ec39SRoland Dreier /* 1576aef9ec39SRoland Dreier * Topspin/Cisco SRP gateways incorrectly send 1577aef9ec39SRoland Dreier * reject reason code 25 when they mean 24 1578aef9ec39SRoland Dreier * (port redirect). 1579aef9ec39SRoland Dreier */ 1580aef9ec39SRoland Dreier memcpy(target->path.dgid.raw, 1581aef9ec39SRoland Dreier event->param.rej_rcvd.ari, 16); 1582aef9ec39SRoland Dreier 15837aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, shost, 15847aa54bd7SDavid Dillow PFX "Topspin/Cisco redirect to target port GID %016llx%016llx\n", 1585aef9ec39SRoland Dreier (unsigned long long) be64_to_cpu(target->path.dgid.global.subnet_prefix), 1586aef9ec39SRoland Dreier (unsigned long long) be64_to_cpu(target->path.dgid.global.interface_id)); 1587aef9ec39SRoland Dreier 1588aef9ec39SRoland Dreier target->status = SRP_PORT_REDIRECT; 1589aef9ec39SRoland Dreier } else { 15907aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, 15917aa54bd7SDavid Dillow " REJ reason: IB_CM_REJ_PORT_REDIRECT\n"); 1592aef9ec39SRoland Dreier target->status = -ECONNRESET; 1593aef9ec39SRoland Dreier } 1594aef9ec39SRoland Dreier break; 1595aef9ec39SRoland Dreier 1596aef9ec39SRoland Dreier case IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID: 15977aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, 15987aa54bd7SDavid Dillow " REJ reason: IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID\n"); 1599aef9ec39SRoland Dreier target->status = -ECONNRESET; 1600aef9ec39SRoland Dreier break; 1601aef9ec39SRoland Dreier 1602aef9ec39SRoland Dreier case IB_CM_REJ_CONSUMER_DEFINED: 1603aef9ec39SRoland Dreier opcode = *(u8 *) event->private_data; 1604aef9ec39SRoland Dreier if (opcode == SRP_LOGIN_REJ) { 1605aef9ec39SRoland Dreier struct srp_login_rej *rej = event->private_data; 1606aef9ec39SRoland Dreier u32 reason = be32_to_cpu(rej->reason); 1607aef9ec39SRoland Dreier 1608aef9ec39SRoland Dreier if (reason == SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE) 16097aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, 16107aa54bd7SDavid Dillow PFX "SRP_LOGIN_REJ: requested max_it_iu_len too large\n"); 1611aef9ec39SRoland Dreier else 16127aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, 16137aa54bd7SDavid Dillow PFX "SRP LOGIN REJECTED, reason 0x%08x\n", reason); 1614aef9ec39SRoland Dreier } else 16157aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, 16167aa54bd7SDavid Dillow " REJ reason: IB_CM_REJ_CONSUMER_DEFINED," 1617aef9ec39SRoland Dreier " opcode 0x%02x\n", opcode); 1618aef9ec39SRoland Dreier target->status = -ECONNRESET; 1619aef9ec39SRoland Dreier break; 1620aef9ec39SRoland Dreier 16219fe4bcf4SDavid Dillow case IB_CM_REJ_STALE_CONN: 16229fe4bcf4SDavid Dillow shost_printk(KERN_WARNING, shost, " REJ reason: stale connection\n"); 16239fe4bcf4SDavid Dillow target->status = SRP_STALE_CONN; 16249fe4bcf4SDavid Dillow break; 16259fe4bcf4SDavid Dillow 1626aef9ec39SRoland Dreier default: 16277aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, " REJ reason 0x%x\n", 1628aef9ec39SRoland Dreier event->param.rej_rcvd.reason); 1629aef9ec39SRoland Dreier target->status = -ECONNRESET; 1630aef9ec39SRoland Dreier } 1631aef9ec39SRoland Dreier } 1632aef9ec39SRoland Dreier 1633aef9ec39SRoland Dreier static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) 1634aef9ec39SRoland Dreier { 1635aef9ec39SRoland Dreier struct srp_target_port *target = cm_id->context; 1636aef9ec39SRoland Dreier int comp = 0; 1637aef9ec39SRoland Dreier 1638aef9ec39SRoland Dreier switch (event->event) { 1639aef9ec39SRoland Dreier case IB_CM_REQ_ERROR: 16407aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, target->scsi_host, 16417aa54bd7SDavid Dillow PFX "Sending CM REQ failed\n"); 1642aef9ec39SRoland Dreier comp = 1; 1643aef9ec39SRoland Dreier target->status = -ECONNRESET; 1644aef9ec39SRoland Dreier break; 1645aef9ec39SRoland Dreier 1646aef9ec39SRoland Dreier case IB_CM_REP_RECEIVED: 1647aef9ec39SRoland Dreier comp = 1; 1648961e0be8SDavid Dillow srp_cm_rep_handler(cm_id, event->private_data, target); 1649aef9ec39SRoland Dreier break; 1650aef9ec39SRoland Dreier 1651aef9ec39SRoland Dreier case IB_CM_REJ_RECEIVED: 16527aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, target->scsi_host, PFX "REJ received\n"); 1653aef9ec39SRoland Dreier comp = 1; 1654aef9ec39SRoland Dreier 1655aef9ec39SRoland Dreier srp_cm_rej_handler(cm_id, event, target); 1656aef9ec39SRoland Dreier break; 1657aef9ec39SRoland Dreier 1658b7ac4ab4SIshai Rabinovitz case IB_CM_DREQ_RECEIVED: 16597aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 16607aa54bd7SDavid Dillow PFX "DREQ received - connection closed\n"); 1661294c875aSBart Van Assche srp_change_conn_state(target, false); 1662b7ac4ab4SIshai Rabinovitz if (ib_send_cm_drep(cm_id, NULL, 0)) 16637aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 16647aa54bd7SDavid Dillow PFX "Sending CM DREP failed\n"); 1665aef9ec39SRoland Dreier break; 1666aef9ec39SRoland Dreier 1667aef9ec39SRoland Dreier case IB_CM_TIMEWAIT_EXIT: 16687aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 16697aa54bd7SDavid Dillow PFX "connection closed\n"); 1670aef9ec39SRoland Dreier 1671aef9ec39SRoland Dreier target->status = 0; 1672aef9ec39SRoland Dreier break; 1673aef9ec39SRoland Dreier 1674b7ac4ab4SIshai Rabinovitz case IB_CM_MRA_RECEIVED: 1675b7ac4ab4SIshai Rabinovitz case IB_CM_DREQ_ERROR: 1676b7ac4ab4SIshai Rabinovitz case IB_CM_DREP_RECEIVED: 1677b7ac4ab4SIshai Rabinovitz break; 1678b7ac4ab4SIshai Rabinovitz 1679aef9ec39SRoland Dreier default: 16807aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 16817aa54bd7SDavid Dillow PFX "Unhandled CM event %d\n", event->event); 1682aef9ec39SRoland Dreier break; 1683aef9ec39SRoland Dreier } 1684aef9ec39SRoland Dreier 1685aef9ec39SRoland Dreier if (comp) 1686aef9ec39SRoland Dreier complete(&target->done); 1687aef9ec39SRoland Dreier 1688aef9ec39SRoland Dreier return 0; 1689aef9ec39SRoland Dreier } 1690aef9ec39SRoland Dreier 1691d945e1dfSRoland Dreier static int srp_send_tsk_mgmt(struct srp_target_port *target, 1692f8b6e31eSDavid Dillow u64 req_tag, unsigned int lun, u8 func) 1693aef9ec39SRoland Dreier { 169419081f31SDavid Dillow struct ib_device *dev = target->srp_host->srp_dev->dev; 1695aef9ec39SRoland Dreier struct srp_iu *iu; 1696aef9ec39SRoland Dreier struct srp_tsk_mgmt *tsk_mgmt; 1697aef9ec39SRoland Dreier 1698f8b6e31eSDavid Dillow init_completion(&target->tsk_mgmt_done); 1699aef9ec39SRoland Dreier 1700e9684678SBart Van Assche spin_lock_irq(&target->lock); 1701bb12588aSDavid Dillow iu = __srp_get_tx_iu(target, SRP_IU_TSK_MGMT); 1702e9684678SBart Van Assche spin_unlock_irq(&target->lock); 170376c75b25SBart Van Assche 1704aef9ec39SRoland Dreier if (!iu) 170576c75b25SBart Van Assche return -1; 1706aef9ec39SRoland Dreier 170719081f31SDavid Dillow ib_dma_sync_single_for_cpu(dev, iu->dma, sizeof *tsk_mgmt, 170819081f31SDavid Dillow DMA_TO_DEVICE); 1709aef9ec39SRoland Dreier tsk_mgmt = iu->buf; 1710aef9ec39SRoland Dreier memset(tsk_mgmt, 0, sizeof *tsk_mgmt); 1711aef9ec39SRoland Dreier 1712aef9ec39SRoland Dreier tsk_mgmt->opcode = SRP_TSK_MGMT; 1713f8b6e31eSDavid Dillow tsk_mgmt->lun = cpu_to_be64((u64) lun << 48); 1714f8b6e31eSDavid Dillow tsk_mgmt->tag = req_tag | SRP_TAG_TSK_MGMT; 1715aef9ec39SRoland Dreier tsk_mgmt->tsk_mgmt_func = func; 1716f8b6e31eSDavid Dillow tsk_mgmt->task_tag = req_tag; 1717aef9ec39SRoland Dreier 171819081f31SDavid Dillow ib_dma_sync_single_for_device(dev, iu->dma, sizeof *tsk_mgmt, 171919081f31SDavid Dillow DMA_TO_DEVICE); 172076c75b25SBart Van Assche if (srp_post_send(target, iu, sizeof *tsk_mgmt)) { 172176c75b25SBart Van Assche srp_put_tx_iu(target, iu, SRP_IU_TSK_MGMT); 172276c75b25SBart Van Assche return -1; 172376c75b25SBart Van Assche } 1724d945e1dfSRoland Dreier 1725f8b6e31eSDavid Dillow if (!wait_for_completion_timeout(&target->tsk_mgmt_done, 1726aef9ec39SRoland Dreier msecs_to_jiffies(SRP_ABORT_TIMEOUT_MS))) 1727d945e1dfSRoland Dreier return -1; 1728aef9ec39SRoland Dreier 1729d945e1dfSRoland Dreier return 0; 1730d945e1dfSRoland Dreier } 1731d945e1dfSRoland Dreier 1732aef9ec39SRoland Dreier static int srp_abort(struct scsi_cmnd *scmnd) 1733aef9ec39SRoland Dreier { 1734d945e1dfSRoland Dreier struct srp_target_port *target = host_to_target(scmnd->device->host); 1735f8b6e31eSDavid Dillow struct srp_request *req = (struct srp_request *) scmnd->host_scribble; 1736d945e1dfSRoland Dreier 17377aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n"); 1738aef9ec39SRoland Dreier 173922032991SBart Van Assche if (!req || target->qp_in_error || !srp_claim_req(target, req, scmnd)) 17401033ff67SIshai Rabinovitz return FAILED; 174122032991SBart Van Assche srp_send_tsk_mgmt(target, req->index, scmnd->device->lun, 174222032991SBart Van Assche SRP_TSK_ABORT_TASK); 174322032991SBart Van Assche srp_free_req(target, req, scmnd, 0); 1744d945e1dfSRoland Dreier scmnd->result = DID_ABORT << 16; 1745d8536670SBart Van Assche scmnd->scsi_done(scmnd); 1746d945e1dfSRoland Dreier 174722032991SBart Van Assche return SUCCESS; 1748aef9ec39SRoland Dreier } 1749aef9ec39SRoland Dreier 1750aef9ec39SRoland Dreier static int srp_reset_device(struct scsi_cmnd *scmnd) 1751aef9ec39SRoland Dreier { 1752d945e1dfSRoland Dreier struct srp_target_port *target = host_to_target(scmnd->device->host); 1753536ae14eSBart Van Assche int i; 1754d945e1dfSRoland Dreier 17557aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, "SRP reset_device called\n"); 1756aef9ec39SRoland Dreier 17571033ff67SIshai Rabinovitz if (target->qp_in_error) 17581033ff67SIshai Rabinovitz return FAILED; 1759f8b6e31eSDavid Dillow if (srp_send_tsk_mgmt(target, SRP_TAG_NO_REQ, scmnd->device->lun, 1760f8b6e31eSDavid Dillow SRP_TSK_LUN_RESET)) 1761d945e1dfSRoland Dreier return FAILED; 1762f8b6e31eSDavid Dillow if (target->tsk_mgmt_status) 1763d945e1dfSRoland Dreier return FAILED; 1764d945e1dfSRoland Dreier 1765536ae14eSBart Van Assche for (i = 0; i < SRP_CMD_SQ_SIZE; ++i) { 1766536ae14eSBart Van Assche struct srp_request *req = &target->req_ring[i]; 1767f8b6e31eSDavid Dillow if (req->scmnd && req->scmnd->device == scmnd->device) 1768526b4caaSIshai Rabinovitz srp_reset_req(target, req); 1769536ae14eSBart Van Assche } 1770d945e1dfSRoland Dreier 1771d945e1dfSRoland Dreier return SUCCESS; 1772aef9ec39SRoland Dreier } 1773aef9ec39SRoland Dreier 1774aef9ec39SRoland Dreier static int srp_reset_host(struct scsi_cmnd *scmnd) 1775aef9ec39SRoland Dreier { 1776aef9ec39SRoland Dreier struct srp_target_port *target = host_to_target(scmnd->device->host); 1777aef9ec39SRoland Dreier int ret = FAILED; 1778aef9ec39SRoland Dreier 17797aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX "SRP reset_host called\n"); 1780aef9ec39SRoland Dreier 1781aef9ec39SRoland Dreier if (!srp_reconnect_target(target)) 1782aef9ec39SRoland Dreier ret = SUCCESS; 1783aef9ec39SRoland Dreier 1784aef9ec39SRoland Dreier return ret; 1785aef9ec39SRoland Dreier } 1786aef9ec39SRoland Dreier 1787c9b03c1aSBart Van Assche static int srp_slave_configure(struct scsi_device *sdev) 1788c9b03c1aSBart Van Assche { 1789c9b03c1aSBart Van Assche struct Scsi_Host *shost = sdev->host; 1790c9b03c1aSBart Van Assche struct srp_target_port *target = host_to_target(shost); 1791c9b03c1aSBart Van Assche struct request_queue *q = sdev->request_queue; 1792c9b03c1aSBart Van Assche unsigned long timeout; 1793c9b03c1aSBart Van Assche 1794c9b03c1aSBart Van Assche if (sdev->type == TYPE_DISK) { 1795c9b03c1aSBart Van Assche timeout = max_t(unsigned, 30 * HZ, target->rq_tmo_jiffies); 1796c9b03c1aSBart Van Assche blk_queue_rq_timeout(q, timeout); 1797c9b03c1aSBart Van Assche } 1798c9b03c1aSBart Van Assche 1799c9b03c1aSBart Van Assche return 0; 1800c9b03c1aSBart Van Assche } 1801c9b03c1aSBart Van Assche 1802ee959b00STony Jones static ssize_t show_id_ext(struct device *dev, struct device_attribute *attr, 1803ee959b00STony Jones char *buf) 18046ecb0c84SRoland Dreier { 1805ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 18066ecb0c84SRoland Dreier 18076ecb0c84SRoland Dreier return sprintf(buf, "0x%016llx\n", 18086ecb0c84SRoland Dreier (unsigned long long) be64_to_cpu(target->id_ext)); 18096ecb0c84SRoland Dreier } 18106ecb0c84SRoland Dreier 1811ee959b00STony Jones static ssize_t show_ioc_guid(struct device *dev, struct device_attribute *attr, 1812ee959b00STony Jones char *buf) 18136ecb0c84SRoland Dreier { 1814ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 18156ecb0c84SRoland Dreier 18166ecb0c84SRoland Dreier return sprintf(buf, "0x%016llx\n", 18176ecb0c84SRoland Dreier (unsigned long long) be64_to_cpu(target->ioc_guid)); 18186ecb0c84SRoland Dreier } 18196ecb0c84SRoland Dreier 1820ee959b00STony Jones static ssize_t show_service_id(struct device *dev, 1821ee959b00STony Jones struct device_attribute *attr, char *buf) 18226ecb0c84SRoland Dreier { 1823ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 18246ecb0c84SRoland Dreier 18256ecb0c84SRoland Dreier return sprintf(buf, "0x%016llx\n", 18266ecb0c84SRoland Dreier (unsigned long long) be64_to_cpu(target->service_id)); 18276ecb0c84SRoland Dreier } 18286ecb0c84SRoland Dreier 1829ee959b00STony Jones static ssize_t show_pkey(struct device *dev, struct device_attribute *attr, 1830ee959b00STony Jones char *buf) 18316ecb0c84SRoland Dreier { 1832ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 18336ecb0c84SRoland Dreier 18346ecb0c84SRoland Dreier return sprintf(buf, "0x%04x\n", be16_to_cpu(target->path.pkey)); 18356ecb0c84SRoland Dreier } 18366ecb0c84SRoland Dreier 1837ee959b00STony Jones static ssize_t show_dgid(struct device *dev, struct device_attribute *attr, 1838ee959b00STony Jones char *buf) 18396ecb0c84SRoland Dreier { 1840ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 18416ecb0c84SRoland Dreier 18425b095d98SHarvey Harrison return sprintf(buf, "%pI6\n", target->path.dgid.raw); 18436ecb0c84SRoland Dreier } 18446ecb0c84SRoland Dreier 1845ee959b00STony Jones static ssize_t show_orig_dgid(struct device *dev, 1846ee959b00STony Jones struct device_attribute *attr, char *buf) 18473633b3d0SIshai Rabinovitz { 1848ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 18493633b3d0SIshai Rabinovitz 18505b095d98SHarvey Harrison return sprintf(buf, "%pI6\n", target->orig_dgid); 18513633b3d0SIshai Rabinovitz } 18523633b3d0SIshai Rabinovitz 185389de7486SBart Van Assche static ssize_t show_req_lim(struct device *dev, 185489de7486SBart Van Assche struct device_attribute *attr, char *buf) 185589de7486SBart Van Assche { 185689de7486SBart Van Assche struct srp_target_port *target = host_to_target(class_to_shost(dev)); 185789de7486SBart Van Assche 185889de7486SBart Van Assche return sprintf(buf, "%d\n", target->req_lim); 185989de7486SBart Van Assche } 186089de7486SBart Van Assche 1861ee959b00STony Jones static ssize_t show_zero_req_lim(struct device *dev, 1862ee959b00STony Jones struct device_attribute *attr, char *buf) 18636bfa24faSRoland Dreier { 1864ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 18656bfa24faSRoland Dreier 18666bfa24faSRoland Dreier return sprintf(buf, "%d\n", target->zero_req_lim); 18676bfa24faSRoland Dreier } 18686bfa24faSRoland Dreier 1869ee959b00STony Jones static ssize_t show_local_ib_port(struct device *dev, 1870ee959b00STony Jones struct device_attribute *attr, char *buf) 1871ded7f1a1SIshai Rabinovitz { 1872ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 1873ded7f1a1SIshai Rabinovitz 1874ded7f1a1SIshai Rabinovitz return sprintf(buf, "%d\n", target->srp_host->port); 1875ded7f1a1SIshai Rabinovitz } 1876ded7f1a1SIshai Rabinovitz 1877ee959b00STony Jones static ssize_t show_local_ib_device(struct device *dev, 1878ee959b00STony Jones struct device_attribute *attr, char *buf) 1879ded7f1a1SIshai Rabinovitz { 1880ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 1881ded7f1a1SIshai Rabinovitz 188205321937SGreg Kroah-Hartman return sprintf(buf, "%s\n", target->srp_host->srp_dev->dev->name); 1883ded7f1a1SIshai Rabinovitz } 1884ded7f1a1SIshai Rabinovitz 188549248644SDavid Dillow static ssize_t show_cmd_sg_entries(struct device *dev, 188649248644SDavid Dillow struct device_attribute *attr, char *buf) 188749248644SDavid Dillow { 188849248644SDavid Dillow struct srp_target_port *target = host_to_target(class_to_shost(dev)); 188949248644SDavid Dillow 189049248644SDavid Dillow return sprintf(buf, "%u\n", target->cmd_sg_cnt); 189149248644SDavid Dillow } 189249248644SDavid Dillow 1893c07d424dSDavid Dillow static ssize_t show_allow_ext_sg(struct device *dev, 1894c07d424dSDavid Dillow struct device_attribute *attr, char *buf) 1895c07d424dSDavid Dillow { 1896c07d424dSDavid Dillow struct srp_target_port *target = host_to_target(class_to_shost(dev)); 1897c07d424dSDavid Dillow 1898c07d424dSDavid Dillow return sprintf(buf, "%s\n", target->allow_ext_sg ? "true" : "false"); 1899c07d424dSDavid Dillow } 1900c07d424dSDavid Dillow 1901ee959b00STony Jones static DEVICE_ATTR(id_ext, S_IRUGO, show_id_ext, NULL); 1902ee959b00STony Jones static DEVICE_ATTR(ioc_guid, S_IRUGO, show_ioc_guid, NULL); 1903ee959b00STony Jones static DEVICE_ATTR(service_id, S_IRUGO, show_service_id, NULL); 1904ee959b00STony Jones static DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL); 1905ee959b00STony Jones static DEVICE_ATTR(dgid, S_IRUGO, show_dgid, NULL); 1906ee959b00STony Jones static DEVICE_ATTR(orig_dgid, S_IRUGO, show_orig_dgid, NULL); 190789de7486SBart Van Assche static DEVICE_ATTR(req_lim, S_IRUGO, show_req_lim, NULL); 1908ee959b00STony Jones static DEVICE_ATTR(zero_req_lim, S_IRUGO, show_zero_req_lim, NULL); 1909ee959b00STony Jones static DEVICE_ATTR(local_ib_port, S_IRUGO, show_local_ib_port, NULL); 1910ee959b00STony Jones static DEVICE_ATTR(local_ib_device, S_IRUGO, show_local_ib_device, NULL); 191149248644SDavid Dillow static DEVICE_ATTR(cmd_sg_entries, S_IRUGO, show_cmd_sg_entries, NULL); 1912c07d424dSDavid Dillow static DEVICE_ATTR(allow_ext_sg, S_IRUGO, show_allow_ext_sg, NULL); 19136ecb0c84SRoland Dreier 1914ee959b00STony Jones static struct device_attribute *srp_host_attrs[] = { 1915ee959b00STony Jones &dev_attr_id_ext, 1916ee959b00STony Jones &dev_attr_ioc_guid, 1917ee959b00STony Jones &dev_attr_service_id, 1918ee959b00STony Jones &dev_attr_pkey, 1919ee959b00STony Jones &dev_attr_dgid, 1920ee959b00STony Jones &dev_attr_orig_dgid, 192189de7486SBart Van Assche &dev_attr_req_lim, 1922ee959b00STony Jones &dev_attr_zero_req_lim, 1923ee959b00STony Jones &dev_attr_local_ib_port, 1924ee959b00STony Jones &dev_attr_local_ib_device, 192549248644SDavid Dillow &dev_attr_cmd_sg_entries, 1926c07d424dSDavid Dillow &dev_attr_allow_ext_sg, 19276ecb0c84SRoland Dreier NULL 19286ecb0c84SRoland Dreier }; 19296ecb0c84SRoland Dreier 1930aef9ec39SRoland Dreier static struct scsi_host_template srp_template = { 1931aef9ec39SRoland Dreier .module = THIS_MODULE, 1932b7f008fdSRoland Dreier .name = "InfiniBand SRP initiator", 1933b7f008fdSRoland Dreier .proc_name = DRV_NAME, 1934c9b03c1aSBart Van Assche .slave_configure = srp_slave_configure, 1935aef9ec39SRoland Dreier .info = srp_target_info, 1936aef9ec39SRoland Dreier .queuecommand = srp_queuecommand, 1937aef9ec39SRoland Dreier .eh_abort_handler = srp_abort, 1938aef9ec39SRoland Dreier .eh_device_reset_handler = srp_reset_device, 1939aef9ec39SRoland Dreier .eh_host_reset_handler = srp_reset_host, 194049248644SDavid Dillow .sg_tablesize = SRP_DEF_SG_TABLESIZE, 1941dd5e6e38SBart Van Assche .can_queue = SRP_CMD_SQ_SIZE, 1942aef9ec39SRoland Dreier .this_id = -1, 1943dd5e6e38SBart Van Assche .cmd_per_lun = SRP_CMD_SQ_SIZE, 19446ecb0c84SRoland Dreier .use_clustering = ENABLE_CLUSTERING, 19456ecb0c84SRoland Dreier .shost_attrs = srp_host_attrs 1946aef9ec39SRoland Dreier }; 1947aef9ec39SRoland Dreier 1948aef9ec39SRoland Dreier static int srp_add_target(struct srp_host *host, struct srp_target_port *target) 1949aef9ec39SRoland Dreier { 19503236822bSFUJITA Tomonori struct srp_rport_identifiers ids; 19513236822bSFUJITA Tomonori struct srp_rport *rport; 19523236822bSFUJITA Tomonori 1953aef9ec39SRoland Dreier sprintf(target->target_name, "SRP.T10:%016llX", 1954aef9ec39SRoland Dreier (unsigned long long) be64_to_cpu(target->id_ext)); 1955aef9ec39SRoland Dreier 195605321937SGreg Kroah-Hartman if (scsi_add_host(target->scsi_host, host->srp_dev->dev->dma_device)) 1957aef9ec39SRoland Dreier return -ENODEV; 1958aef9ec39SRoland Dreier 19593236822bSFUJITA Tomonori memcpy(ids.port_id, &target->id_ext, 8); 19603236822bSFUJITA Tomonori memcpy(ids.port_id + 8, &target->ioc_guid, 8); 1961aebd5e47SFUJITA Tomonori ids.roles = SRP_RPORT_ROLE_TARGET; 19623236822bSFUJITA Tomonori rport = srp_rport_add(target->scsi_host, &ids); 19633236822bSFUJITA Tomonori if (IS_ERR(rport)) { 19643236822bSFUJITA Tomonori scsi_remove_host(target->scsi_host); 19653236822bSFUJITA Tomonori return PTR_ERR(rport); 19663236822bSFUJITA Tomonori } 19673236822bSFUJITA Tomonori 1968*dc1bdbd9SBart Van Assche rport->lld_data = target; 1969*dc1bdbd9SBart Van Assche 1970b3589fd4SMatthew Wilcox spin_lock(&host->target_lock); 1971aef9ec39SRoland Dreier list_add_tail(&target->list, &host->target_list); 1972b3589fd4SMatthew Wilcox spin_unlock(&host->target_lock); 1973aef9ec39SRoland Dreier 1974aef9ec39SRoland Dreier target->state = SRP_TARGET_LIVE; 1975294c875aSBart Van Assche target->connected = false; 1976aef9ec39SRoland Dreier 1977aef9ec39SRoland Dreier scsi_scan_target(&target->scsi_host->shost_gendev, 19781962a4a1SMatthew Wilcox 0, target->scsi_id, SCAN_WILD_CARD, 0); 1979aef9ec39SRoland Dreier 1980aef9ec39SRoland Dreier return 0; 1981aef9ec39SRoland Dreier } 1982aef9ec39SRoland Dreier 1983ee959b00STony Jones static void srp_release_dev(struct device *dev) 1984aef9ec39SRoland Dreier { 1985aef9ec39SRoland Dreier struct srp_host *host = 1986ee959b00STony Jones container_of(dev, struct srp_host, dev); 1987aef9ec39SRoland Dreier 1988aef9ec39SRoland Dreier complete(&host->released); 1989aef9ec39SRoland Dreier } 1990aef9ec39SRoland Dreier 1991aef9ec39SRoland Dreier static struct class srp_class = { 1992aef9ec39SRoland Dreier .name = "infiniband_srp", 1993ee959b00STony Jones .dev_release = srp_release_dev 1994aef9ec39SRoland Dreier }; 1995aef9ec39SRoland Dreier 1996aef9ec39SRoland Dreier /* 1997aef9ec39SRoland Dreier * Target ports are added by writing 1998aef9ec39SRoland Dreier * 1999aef9ec39SRoland Dreier * id_ext=<SRP ID ext>,ioc_guid=<SRP IOC GUID>,dgid=<dest GID>, 2000aef9ec39SRoland Dreier * pkey=<P_Key>,service_id=<service ID> 2001aef9ec39SRoland Dreier * 2002aef9ec39SRoland Dreier * to the add_target sysfs attribute. 2003aef9ec39SRoland Dreier */ 2004aef9ec39SRoland Dreier enum { 2005aef9ec39SRoland Dreier SRP_OPT_ERR = 0, 2006aef9ec39SRoland Dreier SRP_OPT_ID_EXT = 1 << 0, 2007aef9ec39SRoland Dreier SRP_OPT_IOC_GUID = 1 << 1, 2008aef9ec39SRoland Dreier SRP_OPT_DGID = 1 << 2, 2009aef9ec39SRoland Dreier SRP_OPT_PKEY = 1 << 3, 2010aef9ec39SRoland Dreier SRP_OPT_SERVICE_ID = 1 << 4, 2011aef9ec39SRoland Dreier SRP_OPT_MAX_SECT = 1 << 5, 201252fb2b50SVu Pham SRP_OPT_MAX_CMD_PER_LUN = 1 << 6, 20130c0450dbSRamachandra K SRP_OPT_IO_CLASS = 1 << 7, 201401cb9bcbSIshai Rabinovitz SRP_OPT_INITIATOR_EXT = 1 << 8, 201549248644SDavid Dillow SRP_OPT_CMD_SG_ENTRIES = 1 << 9, 2016c07d424dSDavid Dillow SRP_OPT_ALLOW_EXT_SG = 1 << 10, 2017c07d424dSDavid Dillow SRP_OPT_SG_TABLESIZE = 1 << 11, 2018aef9ec39SRoland Dreier SRP_OPT_ALL = (SRP_OPT_ID_EXT | 2019aef9ec39SRoland Dreier SRP_OPT_IOC_GUID | 2020aef9ec39SRoland Dreier SRP_OPT_DGID | 2021aef9ec39SRoland Dreier SRP_OPT_PKEY | 2022aef9ec39SRoland Dreier SRP_OPT_SERVICE_ID), 2023aef9ec39SRoland Dreier }; 2024aef9ec39SRoland Dreier 2025a447c093SSteven Whitehouse static const match_table_t srp_opt_tokens = { 2026aef9ec39SRoland Dreier { SRP_OPT_ID_EXT, "id_ext=%s" }, 2027aef9ec39SRoland Dreier { SRP_OPT_IOC_GUID, "ioc_guid=%s" }, 2028aef9ec39SRoland Dreier { SRP_OPT_DGID, "dgid=%s" }, 2029aef9ec39SRoland Dreier { SRP_OPT_PKEY, "pkey=%x" }, 2030aef9ec39SRoland Dreier { SRP_OPT_SERVICE_ID, "service_id=%s" }, 2031aef9ec39SRoland Dreier { SRP_OPT_MAX_SECT, "max_sect=%d" }, 203252fb2b50SVu Pham { SRP_OPT_MAX_CMD_PER_LUN, "max_cmd_per_lun=%d" }, 20330c0450dbSRamachandra K { SRP_OPT_IO_CLASS, "io_class=%x" }, 203401cb9bcbSIshai Rabinovitz { SRP_OPT_INITIATOR_EXT, "initiator_ext=%s" }, 203549248644SDavid Dillow { SRP_OPT_CMD_SG_ENTRIES, "cmd_sg_entries=%u" }, 2036c07d424dSDavid Dillow { SRP_OPT_ALLOW_EXT_SG, "allow_ext_sg=%u" }, 2037c07d424dSDavid Dillow { SRP_OPT_SG_TABLESIZE, "sg_tablesize=%u" }, 2038aef9ec39SRoland Dreier { SRP_OPT_ERR, NULL } 2039aef9ec39SRoland Dreier }; 2040aef9ec39SRoland Dreier 2041aef9ec39SRoland Dreier static int srp_parse_options(const char *buf, struct srp_target_port *target) 2042aef9ec39SRoland Dreier { 2043aef9ec39SRoland Dreier char *options, *sep_opt; 2044aef9ec39SRoland Dreier char *p; 2045aef9ec39SRoland Dreier char dgid[3]; 2046aef9ec39SRoland Dreier substring_t args[MAX_OPT_ARGS]; 2047aef9ec39SRoland Dreier int opt_mask = 0; 2048aef9ec39SRoland Dreier int token; 2049aef9ec39SRoland Dreier int ret = -EINVAL; 2050aef9ec39SRoland Dreier int i; 2051aef9ec39SRoland Dreier 2052aef9ec39SRoland Dreier options = kstrdup(buf, GFP_KERNEL); 2053aef9ec39SRoland Dreier if (!options) 2054aef9ec39SRoland Dreier return -ENOMEM; 2055aef9ec39SRoland Dreier 2056aef9ec39SRoland Dreier sep_opt = options; 2057aef9ec39SRoland Dreier while ((p = strsep(&sep_opt, ",")) != NULL) { 2058aef9ec39SRoland Dreier if (!*p) 2059aef9ec39SRoland Dreier continue; 2060aef9ec39SRoland Dreier 2061aef9ec39SRoland Dreier token = match_token(p, srp_opt_tokens, args); 2062aef9ec39SRoland Dreier opt_mask |= token; 2063aef9ec39SRoland Dreier 2064aef9ec39SRoland Dreier switch (token) { 2065aef9ec39SRoland Dreier case SRP_OPT_ID_EXT: 2066aef9ec39SRoland Dreier p = match_strdup(args); 2067a20f3a6dSIshai Rabinovitz if (!p) { 2068a20f3a6dSIshai Rabinovitz ret = -ENOMEM; 2069a20f3a6dSIshai Rabinovitz goto out; 2070a20f3a6dSIshai Rabinovitz } 2071aef9ec39SRoland Dreier target->id_ext = cpu_to_be64(simple_strtoull(p, NULL, 16)); 2072aef9ec39SRoland Dreier kfree(p); 2073aef9ec39SRoland Dreier break; 2074aef9ec39SRoland Dreier 2075aef9ec39SRoland Dreier case SRP_OPT_IOC_GUID: 2076aef9ec39SRoland Dreier p = match_strdup(args); 2077a20f3a6dSIshai Rabinovitz if (!p) { 2078a20f3a6dSIshai Rabinovitz ret = -ENOMEM; 2079a20f3a6dSIshai Rabinovitz goto out; 2080a20f3a6dSIshai Rabinovitz } 2081aef9ec39SRoland Dreier target->ioc_guid = cpu_to_be64(simple_strtoull(p, NULL, 16)); 2082aef9ec39SRoland Dreier kfree(p); 2083aef9ec39SRoland Dreier break; 2084aef9ec39SRoland Dreier 2085aef9ec39SRoland Dreier case SRP_OPT_DGID: 2086aef9ec39SRoland Dreier p = match_strdup(args); 2087a20f3a6dSIshai Rabinovitz if (!p) { 2088a20f3a6dSIshai Rabinovitz ret = -ENOMEM; 2089a20f3a6dSIshai Rabinovitz goto out; 2090a20f3a6dSIshai Rabinovitz } 2091aef9ec39SRoland Dreier if (strlen(p) != 32) { 2092e0bda7d8SBart Van Assche pr_warn("bad dest GID parameter '%s'\n", p); 2093ce1823f0SRoland Dreier kfree(p); 2094aef9ec39SRoland Dreier goto out; 2095aef9ec39SRoland Dreier } 2096aef9ec39SRoland Dreier 2097aef9ec39SRoland Dreier for (i = 0; i < 16; ++i) { 2098aef9ec39SRoland Dreier strlcpy(dgid, p + i * 2, 3); 2099aef9ec39SRoland Dreier target->path.dgid.raw[i] = simple_strtoul(dgid, NULL, 16); 2100aef9ec39SRoland Dreier } 2101bf17c1c7SRoland Dreier kfree(p); 21023633b3d0SIshai Rabinovitz memcpy(target->orig_dgid, target->path.dgid.raw, 16); 2103aef9ec39SRoland Dreier break; 2104aef9ec39SRoland Dreier 2105aef9ec39SRoland Dreier case SRP_OPT_PKEY: 2106aef9ec39SRoland Dreier if (match_hex(args, &token)) { 2107e0bda7d8SBart Van Assche pr_warn("bad P_Key parameter '%s'\n", p); 2108aef9ec39SRoland Dreier goto out; 2109aef9ec39SRoland Dreier } 2110aef9ec39SRoland Dreier target->path.pkey = cpu_to_be16(token); 2111aef9ec39SRoland Dreier break; 2112aef9ec39SRoland Dreier 2113aef9ec39SRoland Dreier case SRP_OPT_SERVICE_ID: 2114aef9ec39SRoland Dreier p = match_strdup(args); 2115a20f3a6dSIshai Rabinovitz if (!p) { 2116a20f3a6dSIshai Rabinovitz ret = -ENOMEM; 2117a20f3a6dSIshai Rabinovitz goto out; 2118a20f3a6dSIshai Rabinovitz } 2119aef9ec39SRoland Dreier target->service_id = cpu_to_be64(simple_strtoull(p, NULL, 16)); 2120247e020eSSean Hefty target->path.service_id = target->service_id; 2121aef9ec39SRoland Dreier kfree(p); 2122aef9ec39SRoland Dreier break; 2123aef9ec39SRoland Dreier 2124aef9ec39SRoland Dreier case SRP_OPT_MAX_SECT: 2125aef9ec39SRoland Dreier if (match_int(args, &token)) { 2126e0bda7d8SBart Van Assche pr_warn("bad max sect parameter '%s'\n", p); 2127aef9ec39SRoland Dreier goto out; 2128aef9ec39SRoland Dreier } 2129aef9ec39SRoland Dreier target->scsi_host->max_sectors = token; 2130aef9ec39SRoland Dreier break; 2131aef9ec39SRoland Dreier 213252fb2b50SVu Pham case SRP_OPT_MAX_CMD_PER_LUN: 213352fb2b50SVu Pham if (match_int(args, &token)) { 2134e0bda7d8SBart Van Assche pr_warn("bad max cmd_per_lun parameter '%s'\n", 2135e0bda7d8SBart Van Assche p); 213652fb2b50SVu Pham goto out; 213752fb2b50SVu Pham } 2138dd5e6e38SBart Van Assche target->scsi_host->cmd_per_lun = min(token, SRP_CMD_SQ_SIZE); 213952fb2b50SVu Pham break; 214052fb2b50SVu Pham 21410c0450dbSRamachandra K case SRP_OPT_IO_CLASS: 21420c0450dbSRamachandra K if (match_hex(args, &token)) { 2143e0bda7d8SBart Van Assche pr_warn("bad IO class parameter '%s'\n", p); 21440c0450dbSRamachandra K goto out; 21450c0450dbSRamachandra K } 21460c0450dbSRamachandra K if (token != SRP_REV10_IB_IO_CLASS && 21470c0450dbSRamachandra K token != SRP_REV16A_IB_IO_CLASS) { 2148e0bda7d8SBart Van Assche pr_warn("unknown IO class parameter value %x specified (use %x or %x).\n", 2149e0bda7d8SBart Van Assche token, SRP_REV10_IB_IO_CLASS, 2150e0bda7d8SBart Van Assche SRP_REV16A_IB_IO_CLASS); 21510c0450dbSRamachandra K goto out; 21520c0450dbSRamachandra K } 21530c0450dbSRamachandra K target->io_class = token; 21540c0450dbSRamachandra K break; 21550c0450dbSRamachandra K 215601cb9bcbSIshai Rabinovitz case SRP_OPT_INITIATOR_EXT: 215701cb9bcbSIshai Rabinovitz p = match_strdup(args); 2158a20f3a6dSIshai Rabinovitz if (!p) { 2159a20f3a6dSIshai Rabinovitz ret = -ENOMEM; 2160a20f3a6dSIshai Rabinovitz goto out; 2161a20f3a6dSIshai Rabinovitz } 216201cb9bcbSIshai Rabinovitz target->initiator_ext = cpu_to_be64(simple_strtoull(p, NULL, 16)); 216301cb9bcbSIshai Rabinovitz kfree(p); 216401cb9bcbSIshai Rabinovitz break; 216501cb9bcbSIshai Rabinovitz 216649248644SDavid Dillow case SRP_OPT_CMD_SG_ENTRIES: 216749248644SDavid Dillow if (match_int(args, &token) || token < 1 || token > 255) { 2168e0bda7d8SBart Van Assche pr_warn("bad max cmd_sg_entries parameter '%s'\n", 2169e0bda7d8SBart Van Assche p); 217049248644SDavid Dillow goto out; 217149248644SDavid Dillow } 217249248644SDavid Dillow target->cmd_sg_cnt = token; 217349248644SDavid Dillow break; 217449248644SDavid Dillow 2175c07d424dSDavid Dillow case SRP_OPT_ALLOW_EXT_SG: 2176c07d424dSDavid Dillow if (match_int(args, &token)) { 2177e0bda7d8SBart Van Assche pr_warn("bad allow_ext_sg parameter '%s'\n", p); 2178c07d424dSDavid Dillow goto out; 2179c07d424dSDavid Dillow } 2180c07d424dSDavid Dillow target->allow_ext_sg = !!token; 2181c07d424dSDavid Dillow break; 2182c07d424dSDavid Dillow 2183c07d424dSDavid Dillow case SRP_OPT_SG_TABLESIZE: 2184c07d424dSDavid Dillow if (match_int(args, &token) || token < 1 || 2185c07d424dSDavid Dillow token > SCSI_MAX_SG_CHAIN_SEGMENTS) { 2186e0bda7d8SBart Van Assche pr_warn("bad max sg_tablesize parameter '%s'\n", 2187e0bda7d8SBart Van Assche p); 2188c07d424dSDavid Dillow goto out; 2189c07d424dSDavid Dillow } 2190c07d424dSDavid Dillow target->sg_tablesize = token; 2191c07d424dSDavid Dillow break; 2192c07d424dSDavid Dillow 2193aef9ec39SRoland Dreier default: 2194e0bda7d8SBart Van Assche pr_warn("unknown parameter or missing value '%s' in target creation request\n", 2195e0bda7d8SBart Van Assche p); 2196aef9ec39SRoland Dreier goto out; 2197aef9ec39SRoland Dreier } 2198aef9ec39SRoland Dreier } 2199aef9ec39SRoland Dreier 2200aef9ec39SRoland Dreier if ((opt_mask & SRP_OPT_ALL) == SRP_OPT_ALL) 2201aef9ec39SRoland Dreier ret = 0; 2202aef9ec39SRoland Dreier else 2203aef9ec39SRoland Dreier for (i = 0; i < ARRAY_SIZE(srp_opt_tokens); ++i) 2204aef9ec39SRoland Dreier if ((srp_opt_tokens[i].token & SRP_OPT_ALL) && 2205aef9ec39SRoland Dreier !(srp_opt_tokens[i].token & opt_mask)) 2206e0bda7d8SBart Van Assche pr_warn("target creation request is missing parameter '%s'\n", 2207aef9ec39SRoland Dreier srp_opt_tokens[i].pattern); 2208aef9ec39SRoland Dreier 2209aef9ec39SRoland Dreier out: 2210aef9ec39SRoland Dreier kfree(options); 2211aef9ec39SRoland Dreier return ret; 2212aef9ec39SRoland Dreier } 2213aef9ec39SRoland Dreier 2214ee959b00STony Jones static ssize_t srp_create_target(struct device *dev, 2215ee959b00STony Jones struct device_attribute *attr, 2216aef9ec39SRoland Dreier const char *buf, size_t count) 2217aef9ec39SRoland Dreier { 2218aef9ec39SRoland Dreier struct srp_host *host = 2219ee959b00STony Jones container_of(dev, struct srp_host, dev); 2220aef9ec39SRoland Dreier struct Scsi_Host *target_host; 2221aef9ec39SRoland Dreier struct srp_target_port *target; 2222c07d424dSDavid Dillow struct ib_device *ibdev = host->srp_dev->dev; 2223c07d424dSDavid Dillow dma_addr_t dma_addr; 22248f26c9ffSDavid Dillow int i, ret; 2225aef9ec39SRoland Dreier 2226aef9ec39SRoland Dreier target_host = scsi_host_alloc(&srp_template, 2227aef9ec39SRoland Dreier sizeof (struct srp_target_port)); 2228aef9ec39SRoland Dreier if (!target_host) 2229aef9ec39SRoland Dreier return -ENOMEM; 2230aef9ec39SRoland Dreier 22313236822bSFUJITA Tomonori target_host->transportt = ib_srp_transport_template; 2232fd1b6c4aSBart Van Assche target_host->max_channel = 0; 2233fd1b6c4aSBart Van Assche target_host->max_id = 1; 22345f068992SRoland Dreier target_host->max_lun = SRP_MAX_LUN; 22353c8edf0eSArne Redlich target_host->max_cmd_len = sizeof ((struct srp_cmd *) (void *) 0L)->cdb; 22365f068992SRoland Dreier 2237aef9ec39SRoland Dreier target = host_to_target(target_host); 2238aef9ec39SRoland Dreier 22390c0450dbSRamachandra K target->io_class = SRP_REV16A_IB_IO_CLASS; 2240aef9ec39SRoland Dreier target->scsi_host = target_host; 2241aef9ec39SRoland Dreier target->srp_host = host; 22429af76271SDavid Dillow target->lkey = host->srp_dev->mr->lkey; 22439af76271SDavid Dillow target->rkey = host->srp_dev->mr->rkey; 224449248644SDavid Dillow target->cmd_sg_cnt = cmd_sg_entries; 2245c07d424dSDavid Dillow target->sg_tablesize = indirect_sg_entries ? : cmd_sg_entries; 2246c07d424dSDavid Dillow target->allow_ext_sg = allow_ext_sg; 2247aef9ec39SRoland Dreier 2248aef9ec39SRoland Dreier ret = srp_parse_options(buf, target); 2249aef9ec39SRoland Dreier if (ret) 2250aef9ec39SRoland Dreier goto err; 2251aef9ec39SRoland Dreier 2252c07d424dSDavid Dillow if (!host->srp_dev->fmr_pool && !target->allow_ext_sg && 2253c07d424dSDavid Dillow target->cmd_sg_cnt < target->sg_tablesize) { 2254e0bda7d8SBart Van Assche pr_warn("No FMR pool and no external indirect descriptors, limiting sg_tablesize to cmd_sg_cnt\n"); 2255c07d424dSDavid Dillow target->sg_tablesize = target->cmd_sg_cnt; 2256c07d424dSDavid Dillow } 2257c07d424dSDavid Dillow 2258c07d424dSDavid Dillow target_host->sg_tablesize = target->sg_tablesize; 2259c07d424dSDavid Dillow target->indirect_size = target->sg_tablesize * 2260c07d424dSDavid Dillow sizeof (struct srp_direct_buf); 226149248644SDavid Dillow target->max_iu_len = sizeof (struct srp_cmd) + 226249248644SDavid Dillow sizeof (struct srp_indirect_buf) + 226349248644SDavid Dillow target->cmd_sg_cnt * sizeof (struct srp_direct_buf); 226449248644SDavid Dillow 2265ef6c49d8SBart Van Assche INIT_WORK(&target->remove_work, srp_remove_work); 22668f26c9ffSDavid Dillow spin_lock_init(&target->lock); 22678f26c9ffSDavid Dillow INIT_LIST_HEAD(&target->free_tx); 22688f26c9ffSDavid Dillow INIT_LIST_HEAD(&target->free_reqs); 22698f26c9ffSDavid Dillow for (i = 0; i < SRP_CMD_SQ_SIZE; ++i) { 22708f26c9ffSDavid Dillow struct srp_request *req = &target->req_ring[i]; 22718f26c9ffSDavid Dillow 22728f26c9ffSDavid Dillow req->fmr_list = kmalloc(target->cmd_sg_cnt * sizeof (void *), 22738f26c9ffSDavid Dillow GFP_KERNEL); 22748f26c9ffSDavid Dillow req->map_page = kmalloc(SRP_FMR_SIZE * sizeof (void *), 22758f26c9ffSDavid Dillow GFP_KERNEL); 2276c07d424dSDavid Dillow req->indirect_desc = kmalloc(target->indirect_size, GFP_KERNEL); 2277c07d424dSDavid Dillow if (!req->fmr_list || !req->map_page || !req->indirect_desc) 22788f26c9ffSDavid Dillow goto err_free_mem; 22798f26c9ffSDavid Dillow 2280c07d424dSDavid Dillow dma_addr = ib_dma_map_single(ibdev, req->indirect_desc, 2281c07d424dSDavid Dillow target->indirect_size, 2282c07d424dSDavid Dillow DMA_TO_DEVICE); 2283c07d424dSDavid Dillow if (ib_dma_mapping_error(ibdev, dma_addr)) 2284c07d424dSDavid Dillow goto err_free_mem; 2285c07d424dSDavid Dillow 2286c07d424dSDavid Dillow req->indirect_dma_addr = dma_addr; 22878f26c9ffSDavid Dillow req->index = i; 22888f26c9ffSDavid Dillow list_add_tail(&req->list, &target->free_reqs); 22898f26c9ffSDavid Dillow } 22908f26c9ffSDavid Dillow 2291c07d424dSDavid Dillow ib_query_gid(ibdev, host->port, 0, &target->path.sgid); 2292aef9ec39SRoland Dreier 22937aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, target->scsi_host, PFX 22947aa54bd7SDavid Dillow "new target: id_ext %016llx ioc_guid %016llx pkey %04x " 22955b095d98SHarvey Harrison "service_id %016llx dgid %pI6\n", 2296aef9ec39SRoland Dreier (unsigned long long) be64_to_cpu(target->id_ext), 2297aef9ec39SRoland Dreier (unsigned long long) be64_to_cpu(target->ioc_guid), 2298aef9ec39SRoland Dreier be16_to_cpu(target->path.pkey), 2299aef9ec39SRoland Dreier (unsigned long long) be64_to_cpu(target->service_id), 23008867cd7cSHarvey Harrison target->path.dgid.raw); 2301aef9ec39SRoland Dreier 2302aef9ec39SRoland Dreier ret = srp_create_target_ib(target); 2303aef9ec39SRoland Dreier if (ret) 23048f26c9ffSDavid Dillow goto err_free_mem; 2305aef9ec39SRoland Dreier 23069fe4bcf4SDavid Dillow ret = srp_new_cm_id(target); 23079fe4bcf4SDavid Dillow if (ret) 23088f26c9ffSDavid Dillow goto err_free_ib; 2309aef9ec39SRoland Dreier 2310aef9ec39SRoland Dreier ret = srp_connect_target(target); 2311aef9ec39SRoland Dreier if (ret) { 23127aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 23137aa54bd7SDavid Dillow PFX "Connection failed\n"); 2314aef9ec39SRoland Dreier goto err_cm_id; 2315aef9ec39SRoland Dreier } 2316aef9ec39SRoland Dreier 2317aef9ec39SRoland Dreier ret = srp_add_target(host, target); 2318aef9ec39SRoland Dreier if (ret) 2319aef9ec39SRoland Dreier goto err_disconnect; 2320aef9ec39SRoland Dreier 2321aef9ec39SRoland Dreier return count; 2322aef9ec39SRoland Dreier 2323aef9ec39SRoland Dreier err_disconnect: 2324aef9ec39SRoland Dreier srp_disconnect_target(target); 2325aef9ec39SRoland Dreier 2326aef9ec39SRoland Dreier err_cm_id: 2327aef9ec39SRoland Dreier ib_destroy_cm_id(target->cm_id); 2328aef9ec39SRoland Dreier 23298f26c9ffSDavid Dillow err_free_ib: 2330aef9ec39SRoland Dreier srp_free_target_ib(target); 2331aef9ec39SRoland Dreier 23328f26c9ffSDavid Dillow err_free_mem: 23338f26c9ffSDavid Dillow srp_free_req_data(target); 23348f26c9ffSDavid Dillow 2335aef9ec39SRoland Dreier err: 2336aef9ec39SRoland Dreier scsi_host_put(target_host); 2337aef9ec39SRoland Dreier 2338aef9ec39SRoland Dreier return ret; 2339aef9ec39SRoland Dreier } 2340aef9ec39SRoland Dreier 2341ee959b00STony Jones static DEVICE_ATTR(add_target, S_IWUSR, NULL, srp_create_target); 2342aef9ec39SRoland Dreier 2343ee959b00STony Jones static ssize_t show_ibdev(struct device *dev, struct device_attribute *attr, 2344ee959b00STony Jones char *buf) 2345aef9ec39SRoland Dreier { 2346ee959b00STony Jones struct srp_host *host = container_of(dev, struct srp_host, dev); 2347aef9ec39SRoland Dreier 234805321937SGreg Kroah-Hartman return sprintf(buf, "%s\n", host->srp_dev->dev->name); 2349aef9ec39SRoland Dreier } 2350aef9ec39SRoland Dreier 2351ee959b00STony Jones static DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL); 2352aef9ec39SRoland Dreier 2353ee959b00STony Jones static ssize_t show_port(struct device *dev, struct device_attribute *attr, 2354ee959b00STony Jones char *buf) 2355aef9ec39SRoland Dreier { 2356ee959b00STony Jones struct srp_host *host = container_of(dev, struct srp_host, dev); 2357aef9ec39SRoland Dreier 2358aef9ec39SRoland Dreier return sprintf(buf, "%d\n", host->port); 2359aef9ec39SRoland Dreier } 2360aef9ec39SRoland Dreier 2361ee959b00STony Jones static DEVICE_ATTR(port, S_IRUGO, show_port, NULL); 2362aef9ec39SRoland Dreier 2363f5358a17SRoland Dreier static struct srp_host *srp_add_port(struct srp_device *device, u8 port) 2364aef9ec39SRoland Dreier { 2365aef9ec39SRoland Dreier struct srp_host *host; 2366aef9ec39SRoland Dreier 2367aef9ec39SRoland Dreier host = kzalloc(sizeof *host, GFP_KERNEL); 2368aef9ec39SRoland Dreier if (!host) 2369aef9ec39SRoland Dreier return NULL; 2370aef9ec39SRoland Dreier 2371aef9ec39SRoland Dreier INIT_LIST_HEAD(&host->target_list); 2372b3589fd4SMatthew Wilcox spin_lock_init(&host->target_lock); 2373aef9ec39SRoland Dreier init_completion(&host->released); 237405321937SGreg Kroah-Hartman host->srp_dev = device; 2375aef9ec39SRoland Dreier host->port = port; 2376aef9ec39SRoland Dreier 2377ee959b00STony Jones host->dev.class = &srp_class; 2378ee959b00STony Jones host->dev.parent = device->dev->dma_device; 2379d927e38cSKay Sievers dev_set_name(&host->dev, "srp-%s-%d", device->dev->name, port); 2380aef9ec39SRoland Dreier 2381ee959b00STony Jones if (device_register(&host->dev)) 2382f5358a17SRoland Dreier goto free_host; 2383ee959b00STony Jones if (device_create_file(&host->dev, &dev_attr_add_target)) 2384aef9ec39SRoland Dreier goto err_class; 2385ee959b00STony Jones if (device_create_file(&host->dev, &dev_attr_ibdev)) 2386aef9ec39SRoland Dreier goto err_class; 2387ee959b00STony Jones if (device_create_file(&host->dev, &dev_attr_port)) 2388aef9ec39SRoland Dreier goto err_class; 2389aef9ec39SRoland Dreier 2390aef9ec39SRoland Dreier return host; 2391aef9ec39SRoland Dreier 2392aef9ec39SRoland Dreier err_class: 2393ee959b00STony Jones device_unregister(&host->dev); 2394aef9ec39SRoland Dreier 2395f5358a17SRoland Dreier free_host: 2396aef9ec39SRoland Dreier kfree(host); 2397aef9ec39SRoland Dreier 2398aef9ec39SRoland Dreier return NULL; 2399aef9ec39SRoland Dreier } 2400aef9ec39SRoland Dreier 2401aef9ec39SRoland Dreier static void srp_add_one(struct ib_device *device) 2402aef9ec39SRoland Dreier { 2403f5358a17SRoland Dreier struct srp_device *srp_dev; 2404f5358a17SRoland Dreier struct ib_device_attr *dev_attr; 2405f5358a17SRoland Dreier struct ib_fmr_pool_param fmr_param; 2406aef9ec39SRoland Dreier struct srp_host *host; 2407be8b9814SDavid Dillow int max_pages_per_fmr, fmr_page_shift, s, e, p; 2408aef9ec39SRoland Dreier 2409f5358a17SRoland Dreier dev_attr = kmalloc(sizeof *dev_attr, GFP_KERNEL); 2410f5358a17SRoland Dreier if (!dev_attr) 2411cf311cd4SSean Hefty return; 2412aef9ec39SRoland Dreier 2413f5358a17SRoland Dreier if (ib_query_device(device, dev_attr)) { 2414e0bda7d8SBart Van Assche pr_warn("Query device failed for %s\n", device->name); 2415f5358a17SRoland Dreier goto free_attr; 2416f5358a17SRoland Dreier } 2417f5358a17SRoland Dreier 2418f5358a17SRoland Dreier srp_dev = kmalloc(sizeof *srp_dev, GFP_KERNEL); 2419f5358a17SRoland Dreier if (!srp_dev) 2420f5358a17SRoland Dreier goto free_attr; 2421f5358a17SRoland Dreier 2422f5358a17SRoland Dreier /* 2423f5358a17SRoland Dreier * Use the smallest page size supported by the HCA, down to a 24248f26c9ffSDavid Dillow * minimum of 4096 bytes. We're unlikely to build large sglists 24258f26c9ffSDavid Dillow * out of smaller entries. 2426f5358a17SRoland Dreier */ 24278f26c9ffSDavid Dillow fmr_page_shift = max(12, ffs(dev_attr->page_size_cap) - 1); 24288f26c9ffSDavid Dillow srp_dev->fmr_page_size = 1 << fmr_page_shift; 2429bf628dc2SRoland Dreier srp_dev->fmr_page_mask = ~((u64) srp_dev->fmr_page_size - 1); 24308f26c9ffSDavid Dillow srp_dev->fmr_max_size = srp_dev->fmr_page_size * SRP_FMR_SIZE; 2431f5358a17SRoland Dreier 2432f5358a17SRoland Dreier INIT_LIST_HEAD(&srp_dev->dev_list); 2433f5358a17SRoland Dreier 2434f5358a17SRoland Dreier srp_dev->dev = device; 2435f5358a17SRoland Dreier srp_dev->pd = ib_alloc_pd(device); 2436f5358a17SRoland Dreier if (IS_ERR(srp_dev->pd)) 2437f5358a17SRoland Dreier goto free_dev; 2438f5358a17SRoland Dreier 2439f5358a17SRoland Dreier srp_dev->mr = ib_get_dma_mr(srp_dev->pd, 2440f5358a17SRoland Dreier IB_ACCESS_LOCAL_WRITE | 2441f5358a17SRoland Dreier IB_ACCESS_REMOTE_READ | 2442f5358a17SRoland Dreier IB_ACCESS_REMOTE_WRITE); 2443f5358a17SRoland Dreier if (IS_ERR(srp_dev->mr)) 2444f5358a17SRoland Dreier goto err_pd; 2445f5358a17SRoland Dreier 2446be8b9814SDavid Dillow for (max_pages_per_fmr = SRP_FMR_SIZE; 2447be8b9814SDavid Dillow max_pages_per_fmr >= SRP_FMR_MIN_SIZE; 2448be8b9814SDavid Dillow max_pages_per_fmr /= 2, srp_dev->fmr_max_size /= 2) { 2449f5358a17SRoland Dreier memset(&fmr_param, 0, sizeof fmr_param); 2450f5358a17SRoland Dreier fmr_param.pool_size = SRP_FMR_POOL_SIZE; 2451f5358a17SRoland Dreier fmr_param.dirty_watermark = SRP_FMR_DIRTY_SIZE; 2452f5358a17SRoland Dreier fmr_param.cache = 1; 2453be8b9814SDavid Dillow fmr_param.max_pages_per_fmr = max_pages_per_fmr; 24548f26c9ffSDavid Dillow fmr_param.page_shift = fmr_page_shift; 2455f5358a17SRoland Dreier fmr_param.access = (IB_ACCESS_LOCAL_WRITE | 2456f5358a17SRoland Dreier IB_ACCESS_REMOTE_WRITE | 2457f5358a17SRoland Dreier IB_ACCESS_REMOTE_READ); 2458f5358a17SRoland Dreier 2459f5358a17SRoland Dreier srp_dev->fmr_pool = ib_create_fmr_pool(srp_dev->pd, &fmr_param); 2460be8b9814SDavid Dillow if (!IS_ERR(srp_dev->fmr_pool)) 2461be8b9814SDavid Dillow break; 2462be8b9814SDavid Dillow } 2463be8b9814SDavid Dillow 2464f5358a17SRoland Dreier if (IS_ERR(srp_dev->fmr_pool)) 2465f5358a17SRoland Dreier srp_dev->fmr_pool = NULL; 2466aef9ec39SRoland Dreier 246707ebafbaSTom Tucker if (device->node_type == RDMA_NODE_IB_SWITCH) { 2468aef9ec39SRoland Dreier s = 0; 2469aef9ec39SRoland Dreier e = 0; 2470aef9ec39SRoland Dreier } else { 2471aef9ec39SRoland Dreier s = 1; 2472aef9ec39SRoland Dreier e = device->phys_port_cnt; 2473aef9ec39SRoland Dreier } 2474aef9ec39SRoland Dreier 2475aef9ec39SRoland Dreier for (p = s; p <= e; ++p) { 2476f5358a17SRoland Dreier host = srp_add_port(srp_dev, p); 2477aef9ec39SRoland Dreier if (host) 2478f5358a17SRoland Dreier list_add_tail(&host->list, &srp_dev->dev_list); 2479aef9ec39SRoland Dreier } 2480aef9ec39SRoland Dreier 2481f5358a17SRoland Dreier ib_set_client_data(device, &srp_client, srp_dev); 2482f5358a17SRoland Dreier 2483f5358a17SRoland Dreier goto free_attr; 2484f5358a17SRoland Dreier 2485f5358a17SRoland Dreier err_pd: 2486f5358a17SRoland Dreier ib_dealloc_pd(srp_dev->pd); 2487f5358a17SRoland Dreier 2488f5358a17SRoland Dreier free_dev: 2489f5358a17SRoland Dreier kfree(srp_dev); 2490f5358a17SRoland Dreier 2491f5358a17SRoland Dreier free_attr: 2492f5358a17SRoland Dreier kfree(dev_attr); 2493aef9ec39SRoland Dreier } 2494aef9ec39SRoland Dreier 2495aef9ec39SRoland Dreier static void srp_remove_one(struct ib_device *device) 2496aef9ec39SRoland Dreier { 2497f5358a17SRoland Dreier struct srp_device *srp_dev; 2498aef9ec39SRoland Dreier struct srp_host *host, *tmp_host; 2499ef6c49d8SBart Van Assche struct srp_target_port *target; 2500aef9ec39SRoland Dreier 2501f5358a17SRoland Dreier srp_dev = ib_get_client_data(device, &srp_client); 2502aef9ec39SRoland Dreier 2503f5358a17SRoland Dreier list_for_each_entry_safe(host, tmp_host, &srp_dev->dev_list, list) { 2504ee959b00STony Jones device_unregister(&host->dev); 2505aef9ec39SRoland Dreier /* 2506aef9ec39SRoland Dreier * Wait for the sysfs entry to go away, so that no new 2507aef9ec39SRoland Dreier * target ports can be created. 2508aef9ec39SRoland Dreier */ 2509aef9ec39SRoland Dreier wait_for_completion(&host->released); 2510aef9ec39SRoland Dreier 2511aef9ec39SRoland Dreier /* 2512ef6c49d8SBart Van Assche * Remove all target ports. 2513aef9ec39SRoland Dreier */ 2514b3589fd4SMatthew Wilcox spin_lock(&host->target_lock); 2515ef6c49d8SBart Van Assche list_for_each_entry(target, &host->target_list, list) 2516ef6c49d8SBart Van Assche srp_queue_remove_work(target); 2517b3589fd4SMatthew Wilcox spin_unlock(&host->target_lock); 2518aef9ec39SRoland Dreier 2519aef9ec39SRoland Dreier /* 2520ef6c49d8SBart Van Assche * Wait for target port removal tasks. 2521aef9ec39SRoland Dreier */ 2522ef6c49d8SBart Van Assche flush_workqueue(system_long_wq); 2523aef9ec39SRoland Dreier 2524aef9ec39SRoland Dreier kfree(host); 2525aef9ec39SRoland Dreier } 2526aef9ec39SRoland Dreier 2527f5358a17SRoland Dreier if (srp_dev->fmr_pool) 2528f5358a17SRoland Dreier ib_destroy_fmr_pool(srp_dev->fmr_pool); 2529f5358a17SRoland Dreier ib_dereg_mr(srp_dev->mr); 2530f5358a17SRoland Dreier ib_dealloc_pd(srp_dev->pd); 2531f5358a17SRoland Dreier 2532f5358a17SRoland Dreier kfree(srp_dev); 2533aef9ec39SRoland Dreier } 2534aef9ec39SRoland Dreier 25353236822bSFUJITA Tomonori static struct srp_function_template ib_srp_transport_functions = { 2536*dc1bdbd9SBart Van Assche .rport_delete = srp_rport_delete, 25373236822bSFUJITA Tomonori }; 25383236822bSFUJITA Tomonori 2539aef9ec39SRoland Dreier static int __init srp_init_module(void) 2540aef9ec39SRoland Dreier { 2541aef9ec39SRoland Dreier int ret; 2542aef9ec39SRoland Dreier 2543dcb4cb85SBart Van Assche BUILD_BUG_ON(FIELD_SIZEOF(struct ib_wc, wr_id) < sizeof(void *)); 2544dd5e6e38SBart Van Assche 254549248644SDavid Dillow if (srp_sg_tablesize) { 2546e0bda7d8SBart Van Assche pr_warn("srp_sg_tablesize is deprecated, please use cmd_sg_entries\n"); 254749248644SDavid Dillow if (!cmd_sg_entries) 254849248644SDavid Dillow cmd_sg_entries = srp_sg_tablesize; 254949248644SDavid Dillow } 255049248644SDavid Dillow 255149248644SDavid Dillow if (!cmd_sg_entries) 255249248644SDavid Dillow cmd_sg_entries = SRP_DEF_SG_TABLESIZE; 255349248644SDavid Dillow 255449248644SDavid Dillow if (cmd_sg_entries > 255) { 2555e0bda7d8SBart Van Assche pr_warn("Clamping cmd_sg_entries to 255\n"); 255649248644SDavid Dillow cmd_sg_entries = 255; 25571e89a194SDavid Dillow } 25581e89a194SDavid Dillow 2559c07d424dSDavid Dillow if (!indirect_sg_entries) 2560c07d424dSDavid Dillow indirect_sg_entries = cmd_sg_entries; 2561c07d424dSDavid Dillow else if (indirect_sg_entries < cmd_sg_entries) { 2562e0bda7d8SBart Van Assche pr_warn("Bumping up indirect_sg_entries to match cmd_sg_entries (%u)\n", 2563e0bda7d8SBart Van Assche cmd_sg_entries); 2564c07d424dSDavid Dillow indirect_sg_entries = cmd_sg_entries; 2565c07d424dSDavid Dillow } 2566c07d424dSDavid Dillow 25673236822bSFUJITA Tomonori ib_srp_transport_template = 25683236822bSFUJITA Tomonori srp_attach_transport(&ib_srp_transport_functions); 25693236822bSFUJITA Tomonori if (!ib_srp_transport_template) 25703236822bSFUJITA Tomonori return -ENOMEM; 25713236822bSFUJITA Tomonori 2572aef9ec39SRoland Dreier ret = class_register(&srp_class); 2573aef9ec39SRoland Dreier if (ret) { 2574e0bda7d8SBart Van Assche pr_err("couldn't register class infiniband_srp\n"); 25753236822bSFUJITA Tomonori srp_release_transport(ib_srp_transport_template); 2576aef9ec39SRoland Dreier return ret; 2577aef9ec39SRoland Dreier } 2578aef9ec39SRoland Dreier 2579c1a0b23bSMichael S. Tsirkin ib_sa_register_client(&srp_sa_client); 2580c1a0b23bSMichael S. Tsirkin 2581aef9ec39SRoland Dreier ret = ib_register_client(&srp_client); 2582aef9ec39SRoland Dreier if (ret) { 2583e0bda7d8SBart Van Assche pr_err("couldn't register IB client\n"); 25843236822bSFUJITA Tomonori srp_release_transport(ib_srp_transport_template); 2585c1a0b23bSMichael S. Tsirkin ib_sa_unregister_client(&srp_sa_client); 2586aef9ec39SRoland Dreier class_unregister(&srp_class); 2587aef9ec39SRoland Dreier return ret; 2588aef9ec39SRoland Dreier } 2589aef9ec39SRoland Dreier 2590aef9ec39SRoland Dreier return 0; 2591aef9ec39SRoland Dreier } 2592aef9ec39SRoland Dreier 2593aef9ec39SRoland Dreier static void __exit srp_cleanup_module(void) 2594aef9ec39SRoland Dreier { 2595aef9ec39SRoland Dreier ib_unregister_client(&srp_client); 2596c1a0b23bSMichael S. Tsirkin ib_sa_unregister_client(&srp_sa_client); 2597aef9ec39SRoland Dreier class_unregister(&srp_class); 25983236822bSFUJITA Tomonori srp_release_transport(ib_srp_transport_template); 2599aef9ec39SRoland Dreier } 2600aef9ec39SRoland Dreier 2601aef9ec39SRoland Dreier module_init(srp_init_module); 2602aef9ec39SRoland Dreier module_exit(srp_cleanup_module); 2603