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 33aef9ec39SRoland Dreier #include <linux/module.h> 34aef9ec39SRoland Dreier #include <linux/init.h> 35aef9ec39SRoland Dreier #include <linux/slab.h> 36aef9ec39SRoland Dreier #include <linux/err.h> 37aef9ec39SRoland Dreier #include <linux/string.h> 38aef9ec39SRoland Dreier #include <linux/parser.h> 39aef9ec39SRoland Dreier #include <linux/random.h> 40de25968cSTim Schmielau #include <linux/jiffies.h> 41aef9ec39SRoland Dreier 42aef9ec39SRoland Dreier #include <asm/atomic.h> 43aef9ec39SRoland Dreier 44aef9ec39SRoland Dreier #include <scsi/scsi.h> 45aef9ec39SRoland Dreier #include <scsi/scsi_device.h> 46aef9ec39SRoland Dreier #include <scsi/scsi_dbg.h> 47aef9ec39SRoland Dreier #include <scsi/srp.h> 483236822bSFUJITA Tomonori #include <scsi/scsi_transport_srp.h> 49aef9ec39SRoland Dreier 50aef9ec39SRoland Dreier #include "ib_srp.h" 51aef9ec39SRoland Dreier 52aef9ec39SRoland Dreier #define DRV_NAME "ib_srp" 53aef9ec39SRoland Dreier #define PFX DRV_NAME ": " 54aef9ec39SRoland Dreier #define DRV_VERSION "0.2" 55aef9ec39SRoland Dreier #define DRV_RELDATE "November 1, 2005" 56aef9ec39SRoland Dreier 57aef9ec39SRoland Dreier MODULE_AUTHOR("Roland Dreier"); 58aef9ec39SRoland Dreier MODULE_DESCRIPTION("InfiniBand SCSI RDMA Protocol initiator " 59aef9ec39SRoland Dreier "v" DRV_VERSION " (" DRV_RELDATE ")"); 60aef9ec39SRoland Dreier MODULE_LICENSE("Dual BSD/GPL"); 61aef9ec39SRoland Dreier 6274b0a15bSVu Pham static int srp_sg_tablesize = SRP_DEF_SG_TABLESIZE; 6374b0a15bSVu Pham static int srp_max_iu_len; 6474b0a15bSVu Pham 6574b0a15bSVu Pham module_param(srp_sg_tablesize, int, 0444); 6674b0a15bSVu Pham MODULE_PARM_DESC(srp_sg_tablesize, 671e89a194SDavid Dillow "Max number of gather/scatter entries per I/O (default is 12, max 255)"); 6874b0a15bSVu Pham 69aef9ec39SRoland Dreier static int topspin_workarounds = 1; 70aef9ec39SRoland Dreier 71aef9ec39SRoland Dreier module_param(topspin_workarounds, int, 0444); 72aef9ec39SRoland Dreier MODULE_PARM_DESC(topspin_workarounds, 73aef9ec39SRoland Dreier "Enable workarounds for Topspin/Cisco SRP target bugs if != 0"); 74aef9ec39SRoland Dreier 75aef9ec39SRoland Dreier static void srp_add_one(struct ib_device *device); 76aef9ec39SRoland Dreier static void srp_remove_one(struct ib_device *device); 779c03dc9fSBart Van Assche static void srp_recv_completion(struct ib_cq *cq, void *target_ptr); 789c03dc9fSBart Van Assche static void srp_send_completion(struct ib_cq *cq, void *target_ptr); 79aef9ec39SRoland Dreier static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event); 80aef9ec39SRoland Dreier 813236822bSFUJITA Tomonori static struct scsi_transport_template *ib_srp_transport_template; 823236822bSFUJITA Tomonori 83aef9ec39SRoland Dreier static struct ib_client srp_client = { 84aef9ec39SRoland Dreier .name = "srp", 85aef9ec39SRoland Dreier .add = srp_add_one, 86aef9ec39SRoland Dreier .remove = srp_remove_one 87aef9ec39SRoland Dreier }; 88aef9ec39SRoland Dreier 89c1a0b23bSMichael S. Tsirkin static struct ib_sa_client srp_sa_client; 90c1a0b23bSMichael S. Tsirkin 91aef9ec39SRoland Dreier static inline struct srp_target_port *host_to_target(struct Scsi_Host *host) 92aef9ec39SRoland Dreier { 93aef9ec39SRoland Dreier return (struct srp_target_port *) host->hostdata; 94aef9ec39SRoland Dreier } 95aef9ec39SRoland Dreier 96aef9ec39SRoland Dreier static const char *srp_target_info(struct Scsi_Host *host) 97aef9ec39SRoland Dreier { 98aef9ec39SRoland Dreier return host_to_target(host)->target_name; 99aef9ec39SRoland Dreier } 100aef9ec39SRoland Dreier 1015d7cbfd6SRoland Dreier static int srp_target_is_topspin(struct srp_target_port *target) 1025d7cbfd6SRoland Dreier { 1035d7cbfd6SRoland Dreier static const u8 topspin_oui[3] = { 0x00, 0x05, 0xad }; 1043d1ff48dSRaghava Kondapalli static const u8 cisco_oui[3] = { 0x00, 0x1b, 0x0d }; 1055d7cbfd6SRoland Dreier 1065d7cbfd6SRoland Dreier return topspin_workarounds && 1073d1ff48dSRaghava Kondapalli (!memcmp(&target->ioc_guid, topspin_oui, sizeof topspin_oui) || 1083d1ff48dSRaghava Kondapalli !memcmp(&target->ioc_guid, cisco_oui, sizeof cisco_oui)); 1095d7cbfd6SRoland Dreier } 1105d7cbfd6SRoland Dreier 111aef9ec39SRoland Dreier static struct srp_iu *srp_alloc_iu(struct srp_host *host, size_t size, 112aef9ec39SRoland Dreier gfp_t gfp_mask, 113aef9ec39SRoland Dreier enum dma_data_direction direction) 114aef9ec39SRoland Dreier { 115aef9ec39SRoland Dreier struct srp_iu *iu; 116aef9ec39SRoland Dreier 117aef9ec39SRoland Dreier iu = kmalloc(sizeof *iu, gfp_mask); 118aef9ec39SRoland Dreier if (!iu) 119aef9ec39SRoland Dreier goto out; 120aef9ec39SRoland Dreier 121aef9ec39SRoland Dreier iu->buf = kzalloc(size, gfp_mask); 122aef9ec39SRoland Dreier if (!iu->buf) 123aef9ec39SRoland Dreier goto out_free_iu; 124aef9ec39SRoland Dreier 12505321937SGreg Kroah-Hartman iu->dma = ib_dma_map_single(host->srp_dev->dev, iu->buf, size, 12605321937SGreg Kroah-Hartman direction); 12705321937SGreg Kroah-Hartman if (ib_dma_mapping_error(host->srp_dev->dev, iu->dma)) 128aef9ec39SRoland Dreier goto out_free_buf; 129aef9ec39SRoland Dreier 130aef9ec39SRoland Dreier iu->size = size; 131aef9ec39SRoland Dreier iu->direction = direction; 132aef9ec39SRoland Dreier 133aef9ec39SRoland Dreier return iu; 134aef9ec39SRoland Dreier 135aef9ec39SRoland Dreier out_free_buf: 136aef9ec39SRoland Dreier kfree(iu->buf); 137aef9ec39SRoland Dreier out_free_iu: 138aef9ec39SRoland Dreier kfree(iu); 139aef9ec39SRoland Dreier out: 140aef9ec39SRoland Dreier return NULL; 141aef9ec39SRoland Dreier } 142aef9ec39SRoland Dreier 143aef9ec39SRoland Dreier static void srp_free_iu(struct srp_host *host, struct srp_iu *iu) 144aef9ec39SRoland Dreier { 145aef9ec39SRoland Dreier if (!iu) 146aef9ec39SRoland Dreier return; 147aef9ec39SRoland Dreier 14805321937SGreg Kroah-Hartman ib_dma_unmap_single(host->srp_dev->dev, iu->dma, iu->size, 14905321937SGreg Kroah-Hartman iu->direction); 150aef9ec39SRoland Dreier kfree(iu->buf); 151aef9ec39SRoland Dreier kfree(iu); 152aef9ec39SRoland Dreier } 153aef9ec39SRoland Dreier 154aef9ec39SRoland Dreier static void srp_qp_event(struct ib_event *event, void *context) 155aef9ec39SRoland Dreier { 156aef9ec39SRoland Dreier printk(KERN_ERR PFX "QP event %d\n", event->event); 157aef9ec39SRoland Dreier } 158aef9ec39SRoland Dreier 159aef9ec39SRoland Dreier static int srp_init_qp(struct srp_target_port *target, 160aef9ec39SRoland Dreier struct ib_qp *qp) 161aef9ec39SRoland Dreier { 162aef9ec39SRoland Dreier struct ib_qp_attr *attr; 163aef9ec39SRoland Dreier int ret; 164aef9ec39SRoland Dreier 165aef9ec39SRoland Dreier attr = kmalloc(sizeof *attr, GFP_KERNEL); 166aef9ec39SRoland Dreier if (!attr) 167aef9ec39SRoland Dreier return -ENOMEM; 168aef9ec39SRoland Dreier 169969a60f9SRoland Dreier ret = ib_find_pkey(target->srp_host->srp_dev->dev, 170aef9ec39SRoland Dreier target->srp_host->port, 171aef9ec39SRoland Dreier be16_to_cpu(target->path.pkey), 172aef9ec39SRoland Dreier &attr->pkey_index); 173aef9ec39SRoland Dreier if (ret) 174aef9ec39SRoland Dreier goto out; 175aef9ec39SRoland Dreier 176aef9ec39SRoland Dreier attr->qp_state = IB_QPS_INIT; 177aef9ec39SRoland Dreier attr->qp_access_flags = (IB_ACCESS_REMOTE_READ | 178aef9ec39SRoland Dreier IB_ACCESS_REMOTE_WRITE); 179aef9ec39SRoland Dreier attr->port_num = target->srp_host->port; 180aef9ec39SRoland Dreier 181aef9ec39SRoland Dreier ret = ib_modify_qp(qp, attr, 182aef9ec39SRoland Dreier IB_QP_STATE | 183aef9ec39SRoland Dreier IB_QP_PKEY_INDEX | 184aef9ec39SRoland Dreier IB_QP_ACCESS_FLAGS | 185aef9ec39SRoland Dreier IB_QP_PORT); 186aef9ec39SRoland Dreier 187aef9ec39SRoland Dreier out: 188aef9ec39SRoland Dreier kfree(attr); 189aef9ec39SRoland Dreier return ret; 190aef9ec39SRoland Dreier } 191aef9ec39SRoland Dreier 1929fe4bcf4SDavid Dillow static int srp_new_cm_id(struct srp_target_port *target) 1939fe4bcf4SDavid Dillow { 1949fe4bcf4SDavid Dillow struct ib_cm_id *new_cm_id; 1959fe4bcf4SDavid Dillow 19605321937SGreg Kroah-Hartman new_cm_id = ib_create_cm_id(target->srp_host->srp_dev->dev, 1979fe4bcf4SDavid Dillow srp_cm_handler, target); 1989fe4bcf4SDavid Dillow if (IS_ERR(new_cm_id)) 1999fe4bcf4SDavid Dillow return PTR_ERR(new_cm_id); 2009fe4bcf4SDavid Dillow 2019fe4bcf4SDavid Dillow if (target->cm_id) 2029fe4bcf4SDavid Dillow ib_destroy_cm_id(target->cm_id); 2039fe4bcf4SDavid Dillow target->cm_id = new_cm_id; 2049fe4bcf4SDavid Dillow 2059fe4bcf4SDavid Dillow return 0; 2069fe4bcf4SDavid Dillow } 2079fe4bcf4SDavid Dillow 208aef9ec39SRoland Dreier static int srp_create_target_ib(struct srp_target_port *target) 209aef9ec39SRoland Dreier { 210aef9ec39SRoland Dreier struct ib_qp_init_attr *init_attr; 211aef9ec39SRoland Dreier int ret; 212aef9ec39SRoland Dreier 213aef9ec39SRoland Dreier init_attr = kzalloc(sizeof *init_attr, GFP_KERNEL); 214aef9ec39SRoland Dreier if (!init_attr) 215aef9ec39SRoland Dreier return -ENOMEM; 216aef9ec39SRoland Dreier 2179c03dc9fSBart Van Assche target->recv_cq = ib_create_cq(target->srp_host->srp_dev->dev, 2189c03dc9fSBart Van Assche srp_recv_completion, NULL, target, SRP_RQ_SIZE, 0); 2199c03dc9fSBart Van Assche if (IS_ERR(target->recv_cq)) { 2209c03dc9fSBart Van Assche ret = PTR_ERR(target->recv_cq); 221da9d2f07SRoland Dreier goto err; 222aef9ec39SRoland Dreier } 223aef9ec39SRoland Dreier 2249c03dc9fSBart Van Assche target->send_cq = ib_create_cq(target->srp_host->srp_dev->dev, 2259c03dc9fSBart Van Assche srp_send_completion, NULL, target, SRP_SQ_SIZE, 0); 2269c03dc9fSBart Van Assche if (IS_ERR(target->send_cq)) { 2279c03dc9fSBart Van Assche ret = PTR_ERR(target->send_cq); 228da9d2f07SRoland Dreier goto err_recv_cq; 2299c03dc9fSBart Van Assche } 2309c03dc9fSBart Van Assche 2319c03dc9fSBart Van Assche ib_req_notify_cq(target->recv_cq, IB_CQ_NEXT_COMP); 232aef9ec39SRoland Dreier 233aef9ec39SRoland Dreier init_attr->event_handler = srp_qp_event; 234aef9ec39SRoland Dreier init_attr->cap.max_send_wr = SRP_SQ_SIZE; 235aef9ec39SRoland Dreier init_attr->cap.max_recv_wr = SRP_RQ_SIZE; 236aef9ec39SRoland Dreier init_attr->cap.max_recv_sge = 1; 237aef9ec39SRoland Dreier init_attr->cap.max_send_sge = 1; 238aef9ec39SRoland Dreier init_attr->sq_sig_type = IB_SIGNAL_ALL_WR; 239aef9ec39SRoland Dreier init_attr->qp_type = IB_QPT_RC; 2409c03dc9fSBart Van Assche init_attr->send_cq = target->send_cq; 2419c03dc9fSBart Van Assche init_attr->recv_cq = target->recv_cq; 242aef9ec39SRoland Dreier 24305321937SGreg Kroah-Hartman target->qp = ib_create_qp(target->srp_host->srp_dev->pd, init_attr); 244aef9ec39SRoland Dreier if (IS_ERR(target->qp)) { 245aef9ec39SRoland Dreier ret = PTR_ERR(target->qp); 246da9d2f07SRoland Dreier goto err_send_cq; 247aef9ec39SRoland Dreier } 248aef9ec39SRoland Dreier 249aef9ec39SRoland Dreier ret = srp_init_qp(target, target->qp); 250da9d2f07SRoland Dreier if (ret) 251da9d2f07SRoland Dreier goto err_qp; 252aef9ec39SRoland Dreier 253da9d2f07SRoland Dreier kfree(init_attr); 254da9d2f07SRoland Dreier return 0; 255da9d2f07SRoland Dreier 256da9d2f07SRoland Dreier err_qp: 257da9d2f07SRoland Dreier ib_destroy_qp(target->qp); 258da9d2f07SRoland Dreier 259da9d2f07SRoland Dreier err_send_cq: 260da9d2f07SRoland Dreier ib_destroy_cq(target->send_cq); 261da9d2f07SRoland Dreier 262da9d2f07SRoland Dreier err_recv_cq: 263da9d2f07SRoland Dreier ib_destroy_cq(target->recv_cq); 264da9d2f07SRoland Dreier 265da9d2f07SRoland Dreier err: 266aef9ec39SRoland Dreier kfree(init_attr); 267aef9ec39SRoland Dreier return ret; 268aef9ec39SRoland Dreier } 269aef9ec39SRoland Dreier 270aef9ec39SRoland Dreier static void srp_free_target_ib(struct srp_target_port *target) 271aef9ec39SRoland Dreier { 272aef9ec39SRoland Dreier int i; 273aef9ec39SRoland Dreier 274aef9ec39SRoland Dreier ib_destroy_qp(target->qp); 2759c03dc9fSBart Van Assche ib_destroy_cq(target->send_cq); 2769c03dc9fSBart Van Assche ib_destroy_cq(target->recv_cq); 277aef9ec39SRoland Dreier 278aef9ec39SRoland Dreier for (i = 0; i < SRP_RQ_SIZE; ++i) 279aef9ec39SRoland Dreier srp_free_iu(target->srp_host, target->rx_ring[i]); 280dd5e6e38SBart Van Assche for (i = 0; i < SRP_SQ_SIZE; ++i) 281aef9ec39SRoland Dreier srp_free_iu(target->srp_host, target->tx_ring[i]); 282aef9ec39SRoland Dreier } 283aef9ec39SRoland Dreier 284aef9ec39SRoland Dreier static void srp_path_rec_completion(int status, 285aef9ec39SRoland Dreier struct ib_sa_path_rec *pathrec, 286aef9ec39SRoland Dreier void *target_ptr) 287aef9ec39SRoland Dreier { 288aef9ec39SRoland Dreier struct srp_target_port *target = target_ptr; 289aef9ec39SRoland Dreier 290aef9ec39SRoland Dreier target->status = status; 291aef9ec39SRoland Dreier if (status) 2927aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 2937aa54bd7SDavid Dillow PFX "Got failed path rec status %d\n", status); 294aef9ec39SRoland Dreier else 295aef9ec39SRoland Dreier target->path = *pathrec; 296aef9ec39SRoland Dreier complete(&target->done); 297aef9ec39SRoland Dreier } 298aef9ec39SRoland Dreier 299aef9ec39SRoland Dreier static int srp_lookup_path(struct srp_target_port *target) 300aef9ec39SRoland Dreier { 301aef9ec39SRoland Dreier target->path.numb_path = 1; 302aef9ec39SRoland Dreier 303aef9ec39SRoland Dreier init_completion(&target->done); 304aef9ec39SRoland Dreier 305c1a0b23bSMichael S. Tsirkin target->path_query_id = ib_sa_path_rec_get(&srp_sa_client, 30605321937SGreg Kroah-Hartman target->srp_host->srp_dev->dev, 307aef9ec39SRoland Dreier target->srp_host->port, 308aef9ec39SRoland Dreier &target->path, 309247e020eSSean Hefty IB_SA_PATH_REC_SERVICE_ID | 310aef9ec39SRoland Dreier IB_SA_PATH_REC_DGID | 311aef9ec39SRoland Dreier IB_SA_PATH_REC_SGID | 312aef9ec39SRoland Dreier IB_SA_PATH_REC_NUMB_PATH | 313aef9ec39SRoland Dreier IB_SA_PATH_REC_PKEY, 314aef9ec39SRoland Dreier SRP_PATH_REC_TIMEOUT_MS, 315aef9ec39SRoland Dreier GFP_KERNEL, 316aef9ec39SRoland Dreier srp_path_rec_completion, 317aef9ec39SRoland Dreier target, &target->path_query); 318aef9ec39SRoland Dreier if (target->path_query_id < 0) 319aef9ec39SRoland Dreier return target->path_query_id; 320aef9ec39SRoland Dreier 321aef9ec39SRoland Dreier wait_for_completion(&target->done); 322aef9ec39SRoland Dreier 323aef9ec39SRoland Dreier if (target->status < 0) 3247aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 3257aa54bd7SDavid Dillow PFX "Path record query failed\n"); 326aef9ec39SRoland Dreier 327aef9ec39SRoland Dreier return target->status; 328aef9ec39SRoland Dreier } 329aef9ec39SRoland Dreier 330aef9ec39SRoland Dreier static int srp_send_req(struct srp_target_port *target) 331aef9ec39SRoland Dreier { 332aef9ec39SRoland Dreier struct { 333aef9ec39SRoland Dreier struct ib_cm_req_param param; 334aef9ec39SRoland Dreier struct srp_login_req priv; 335aef9ec39SRoland Dreier } *req = NULL; 336aef9ec39SRoland Dreier int status; 337aef9ec39SRoland Dreier 338aef9ec39SRoland Dreier req = kzalloc(sizeof *req, GFP_KERNEL); 339aef9ec39SRoland Dreier if (!req) 340aef9ec39SRoland Dreier return -ENOMEM; 341aef9ec39SRoland Dreier 342aef9ec39SRoland Dreier req->param.primary_path = &target->path; 343aef9ec39SRoland Dreier req->param.alternate_path = NULL; 344aef9ec39SRoland Dreier req->param.service_id = target->service_id; 345aef9ec39SRoland Dreier req->param.qp_num = target->qp->qp_num; 346aef9ec39SRoland Dreier req->param.qp_type = target->qp->qp_type; 347aef9ec39SRoland Dreier req->param.private_data = &req->priv; 348aef9ec39SRoland Dreier req->param.private_data_len = sizeof req->priv; 349aef9ec39SRoland Dreier req->param.flow_control = 1; 350aef9ec39SRoland Dreier 351aef9ec39SRoland Dreier get_random_bytes(&req->param.starting_psn, 4); 352aef9ec39SRoland Dreier req->param.starting_psn &= 0xffffff; 353aef9ec39SRoland Dreier 354aef9ec39SRoland Dreier /* 355aef9ec39SRoland Dreier * Pick some arbitrary defaults here; we could make these 356aef9ec39SRoland Dreier * module parameters if anyone cared about setting them. 357aef9ec39SRoland Dreier */ 358aef9ec39SRoland Dreier req->param.responder_resources = 4; 359aef9ec39SRoland Dreier req->param.remote_cm_response_timeout = 20; 360aef9ec39SRoland Dreier req->param.local_cm_response_timeout = 20; 361aef9ec39SRoland Dreier req->param.retry_count = 7; 362aef9ec39SRoland Dreier req->param.rnr_retry_count = 7; 363aef9ec39SRoland Dreier req->param.max_cm_retries = 15; 364aef9ec39SRoland Dreier 365aef9ec39SRoland Dreier req->priv.opcode = SRP_LOGIN_REQ; 366aef9ec39SRoland Dreier req->priv.tag = 0; 36774b0a15bSVu Pham req->priv.req_it_iu_len = cpu_to_be32(srp_max_iu_len); 368aef9ec39SRoland Dreier req->priv.req_buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT | 369aef9ec39SRoland Dreier SRP_BUF_FORMAT_INDIRECT); 3700c0450dbSRamachandra K /* 3710c0450dbSRamachandra K * In the published SRP specification (draft rev. 16a), the 3720c0450dbSRamachandra K * port identifier format is 8 bytes of ID extension followed 3730c0450dbSRamachandra K * by 8 bytes of GUID. Older drafts put the two halves in the 3740c0450dbSRamachandra K * opposite order, so that the GUID comes first. 3750c0450dbSRamachandra K * 3760c0450dbSRamachandra K * Targets conforming to these obsolete drafts can be 3770c0450dbSRamachandra K * recognized by the I/O Class they report. 3780c0450dbSRamachandra K */ 3790c0450dbSRamachandra K if (target->io_class == SRP_REV10_IB_IO_CLASS) { 3800c0450dbSRamachandra K memcpy(req->priv.initiator_port_id, 38101cb9bcbSIshai Rabinovitz &target->path.sgid.global.interface_id, 8); 3820c0450dbSRamachandra K memcpy(req->priv.initiator_port_id + 8, 38301cb9bcbSIshai Rabinovitz &target->initiator_ext, 8); 3840c0450dbSRamachandra K memcpy(req->priv.target_port_id, &target->ioc_guid, 8); 3850c0450dbSRamachandra K memcpy(req->priv.target_port_id + 8, &target->id_ext, 8); 3860c0450dbSRamachandra K } else { 3870c0450dbSRamachandra K memcpy(req->priv.initiator_port_id, 38801cb9bcbSIshai Rabinovitz &target->initiator_ext, 8); 38901cb9bcbSIshai Rabinovitz memcpy(req->priv.initiator_port_id + 8, 39001cb9bcbSIshai Rabinovitz &target->path.sgid.global.interface_id, 8); 3910c0450dbSRamachandra K memcpy(req->priv.target_port_id, &target->id_ext, 8); 3920c0450dbSRamachandra K memcpy(req->priv.target_port_id + 8, &target->ioc_guid, 8); 3930c0450dbSRamachandra K } 3940c0450dbSRamachandra K 395aef9ec39SRoland Dreier /* 396aef9ec39SRoland Dreier * Topspin/Cisco SRP targets will reject our login unless we 39701cb9bcbSIshai Rabinovitz * zero out the first 8 bytes of our initiator port ID and set 39801cb9bcbSIshai Rabinovitz * the second 8 bytes to the local node GUID. 399aef9ec39SRoland Dreier */ 4005d7cbfd6SRoland Dreier if (srp_target_is_topspin(target)) { 4017aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, target->scsi_host, 4027aa54bd7SDavid Dillow PFX "Topspin/Cisco initiator port ID workaround " 403aef9ec39SRoland Dreier "activated for target GUID %016llx\n", 404aef9ec39SRoland Dreier (unsigned long long) be64_to_cpu(target->ioc_guid)); 405aef9ec39SRoland Dreier memset(req->priv.initiator_port_id, 0, 8); 40601cb9bcbSIshai Rabinovitz memcpy(req->priv.initiator_port_id + 8, 40705321937SGreg Kroah-Hartman &target->srp_host->srp_dev->dev->node_guid, 8); 408aef9ec39SRoland Dreier } 409aef9ec39SRoland Dreier 410aef9ec39SRoland Dreier status = ib_send_cm_req(target->cm_id, &req->param); 411aef9ec39SRoland Dreier 412aef9ec39SRoland Dreier kfree(req); 413aef9ec39SRoland Dreier 414aef9ec39SRoland Dreier return status; 415aef9ec39SRoland Dreier } 416aef9ec39SRoland Dreier 417aef9ec39SRoland Dreier static void srp_disconnect_target(struct srp_target_port *target) 418aef9ec39SRoland Dreier { 419aef9ec39SRoland Dreier /* XXX should send SRP_I_LOGOUT request */ 420aef9ec39SRoland Dreier 421aef9ec39SRoland Dreier init_completion(&target->done); 422e6581056SRoland Dreier if (ib_send_cm_dreq(target->cm_id, NULL, 0)) { 4237aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, target->scsi_host, 4247aa54bd7SDavid Dillow PFX "Sending CM DREQ failed\n"); 425e6581056SRoland Dreier return; 426e6581056SRoland Dreier } 427aef9ec39SRoland Dreier wait_for_completion(&target->done); 428aef9ec39SRoland Dreier } 429aef9ec39SRoland Dreier 4309709f0e0SBart Van Assche static bool srp_change_state(struct srp_target_port *target, 4319709f0e0SBart Van Assche enum srp_target_state old, 4329709f0e0SBart Van Assche enum srp_target_state new) 4339709f0e0SBart Van Assche { 4349709f0e0SBart Van Assche bool changed = false; 4359709f0e0SBart Van Assche 436e9684678SBart Van Assche spin_lock_irq(&target->lock); 4379709f0e0SBart Van Assche if (target->state == old) { 4389709f0e0SBart Van Assche target->state = new; 4399709f0e0SBart Van Assche changed = true; 4409709f0e0SBart Van Assche } 441e9684678SBart Van Assche spin_unlock_irq(&target->lock); 4429709f0e0SBart Van Assche return changed; 4439709f0e0SBart Van Assche } 4449709f0e0SBart Van Assche 445c4028958SDavid Howells static void srp_remove_work(struct work_struct *work) 446aef9ec39SRoland Dreier { 447c4028958SDavid Howells struct srp_target_port *target = 448c4028958SDavid Howells container_of(work, struct srp_target_port, work); 449aef9ec39SRoland Dreier 4509709f0e0SBart Van Assche if (!srp_change_state(target, SRP_TARGET_DEAD, SRP_TARGET_REMOVED)) 451aef9ec39SRoland Dreier return; 452aef9ec39SRoland Dreier 453b3589fd4SMatthew Wilcox spin_lock(&target->srp_host->target_lock); 454aef9ec39SRoland Dreier list_del(&target->list); 455b3589fd4SMatthew Wilcox spin_unlock(&target->srp_host->target_lock); 456aef9ec39SRoland Dreier 4573236822bSFUJITA Tomonori srp_remove_host(target->scsi_host); 458aef9ec39SRoland Dreier scsi_remove_host(target->scsi_host); 459aef9ec39SRoland Dreier ib_destroy_cm_id(target->cm_id); 460aef9ec39SRoland Dreier srp_free_target_ib(target); 461aef9ec39SRoland Dreier scsi_host_put(target->scsi_host); 462aef9ec39SRoland Dreier } 463aef9ec39SRoland Dreier 464aef9ec39SRoland Dreier static int srp_connect_target(struct srp_target_port *target) 465aef9ec39SRoland Dreier { 4669fe4bcf4SDavid Dillow int retries = 3; 467aef9ec39SRoland Dreier int ret; 468aef9ec39SRoland Dreier 469aef9ec39SRoland Dreier ret = srp_lookup_path(target); 470aef9ec39SRoland Dreier if (ret) 471aef9ec39SRoland Dreier return ret; 472aef9ec39SRoland Dreier 473aef9ec39SRoland Dreier while (1) { 474aef9ec39SRoland Dreier init_completion(&target->done); 475aef9ec39SRoland Dreier ret = srp_send_req(target); 476aef9ec39SRoland Dreier if (ret) 477aef9ec39SRoland Dreier return ret; 478aef9ec39SRoland Dreier wait_for_completion(&target->done); 479aef9ec39SRoland Dreier 480aef9ec39SRoland Dreier /* 481aef9ec39SRoland Dreier * The CM event handling code will set status to 482aef9ec39SRoland Dreier * SRP_PORT_REDIRECT if we get a port redirect REJ 483aef9ec39SRoland Dreier * back, or SRP_DLID_REDIRECT if we get a lid/qp 484aef9ec39SRoland Dreier * redirect REJ back. 485aef9ec39SRoland Dreier */ 486aef9ec39SRoland Dreier switch (target->status) { 487aef9ec39SRoland Dreier case 0: 488aef9ec39SRoland Dreier return 0; 489aef9ec39SRoland Dreier 490aef9ec39SRoland Dreier case SRP_PORT_REDIRECT: 491aef9ec39SRoland Dreier ret = srp_lookup_path(target); 492aef9ec39SRoland Dreier if (ret) 493aef9ec39SRoland Dreier return ret; 494aef9ec39SRoland Dreier break; 495aef9ec39SRoland Dreier 496aef9ec39SRoland Dreier case SRP_DLID_REDIRECT: 497aef9ec39SRoland Dreier break; 498aef9ec39SRoland Dreier 4999fe4bcf4SDavid Dillow case SRP_STALE_CONN: 5009fe4bcf4SDavid Dillow /* Our current CM id was stale, and is now in timewait. 5019fe4bcf4SDavid Dillow * Try to reconnect with a new one. 5029fe4bcf4SDavid Dillow */ 5039fe4bcf4SDavid Dillow if (!retries-- || srp_new_cm_id(target)) { 5049fe4bcf4SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX 5059fe4bcf4SDavid Dillow "giving up on stale connection\n"); 5069fe4bcf4SDavid Dillow target->status = -ECONNRESET; 5079fe4bcf4SDavid Dillow return target->status; 5089fe4bcf4SDavid Dillow } 5099fe4bcf4SDavid Dillow 5109fe4bcf4SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX 5119fe4bcf4SDavid Dillow "retrying stale connection\n"); 5129fe4bcf4SDavid Dillow break; 5139fe4bcf4SDavid Dillow 514aef9ec39SRoland Dreier default: 515aef9ec39SRoland Dreier return target->status; 516aef9ec39SRoland Dreier } 517aef9ec39SRoland Dreier } 518aef9ec39SRoland Dreier } 519aef9ec39SRoland Dreier 520d945e1dfSRoland Dreier static void srp_unmap_data(struct scsi_cmnd *scmnd, 521d945e1dfSRoland Dreier struct srp_target_port *target, 522d945e1dfSRoland Dreier struct srp_request *req) 523d945e1dfSRoland Dreier { 524bb350d1dSFUJITA Tomonori if (!scsi_sglist(scmnd) || 525d945e1dfSRoland Dreier (scmnd->sc_data_direction != DMA_TO_DEVICE && 526d945e1dfSRoland Dreier scmnd->sc_data_direction != DMA_FROM_DEVICE)) 527d945e1dfSRoland Dreier return; 528d945e1dfSRoland Dreier 529f5358a17SRoland Dreier if (req->fmr) { 530f5358a17SRoland Dreier ib_fmr_pool_unmap(req->fmr); 531f5358a17SRoland Dreier req->fmr = NULL; 532f5358a17SRoland Dreier } 533f5358a17SRoland Dreier 53405321937SGreg Kroah-Hartman ib_dma_unmap_sg(target->srp_host->srp_dev->dev, scsi_sglist(scmnd), 535bb350d1dSFUJITA Tomonori scsi_sg_count(scmnd), scmnd->sc_data_direction); 536d945e1dfSRoland Dreier } 537d945e1dfSRoland Dreier 53894a9174cSBart Van Assche static void srp_remove_req(struct srp_target_port *target, 53994a9174cSBart Van Assche struct srp_request *req, s32 req_lim_delta) 540526b4caaSIshai Rabinovitz { 54194a9174cSBart Van Assche unsigned long flags; 54294a9174cSBart Van Assche 543526b4caaSIshai Rabinovitz srp_unmap_data(req->scmnd, target, req); 544e9684678SBart Van Assche spin_lock_irqsave(&target->lock, flags); 54594a9174cSBart Van Assche target->req_lim += req_lim_delta; 546f8b6e31eSDavid Dillow req->scmnd = NULL; 547536ae14eSBart Van Assche list_add_tail(&req->list, &target->free_reqs); 548e9684678SBart Van Assche spin_unlock_irqrestore(&target->lock, flags); 549526b4caaSIshai Rabinovitz } 550526b4caaSIshai Rabinovitz 551526b4caaSIshai Rabinovitz static void srp_reset_req(struct srp_target_port *target, struct srp_request *req) 552526b4caaSIshai Rabinovitz { 553526b4caaSIshai Rabinovitz req->scmnd->result = DID_RESET << 16; 554526b4caaSIshai Rabinovitz req->scmnd->scsi_done(req->scmnd); 55594a9174cSBart Van Assche srp_remove_req(target, req, 0); 556526b4caaSIshai Rabinovitz } 557526b4caaSIshai Rabinovitz 558aef9ec39SRoland Dreier static int srp_reconnect_target(struct srp_target_port *target) 559aef9ec39SRoland Dreier { 560aef9ec39SRoland Dreier struct ib_qp_attr qp_attr; 561aef9ec39SRoland Dreier struct ib_wc wc; 562dcb4cb85SBart Van Assche int i, ret; 563aef9ec39SRoland Dreier 5649709f0e0SBart Van Assche if (!srp_change_state(target, SRP_TARGET_LIVE, SRP_TARGET_CONNECTING)) 565aef9ec39SRoland Dreier return -EAGAIN; 566aef9ec39SRoland Dreier 567aef9ec39SRoland Dreier srp_disconnect_target(target); 568aef9ec39SRoland Dreier /* 569aef9ec39SRoland Dreier * Now get a new local CM ID so that we avoid confusing the 570aef9ec39SRoland Dreier * target in case things are really fouled up. 571aef9ec39SRoland Dreier */ 5729fe4bcf4SDavid Dillow ret = srp_new_cm_id(target); 5739fe4bcf4SDavid Dillow if (ret) 574aef9ec39SRoland Dreier goto err; 575aef9ec39SRoland Dreier 576aef9ec39SRoland Dreier qp_attr.qp_state = IB_QPS_RESET; 577aef9ec39SRoland Dreier ret = ib_modify_qp(target->qp, &qp_attr, IB_QP_STATE); 578aef9ec39SRoland Dreier if (ret) 579aef9ec39SRoland Dreier goto err; 580aef9ec39SRoland Dreier 581aef9ec39SRoland Dreier ret = srp_init_qp(target, target->qp); 582aef9ec39SRoland Dreier if (ret) 583aef9ec39SRoland Dreier goto err; 584aef9ec39SRoland Dreier 5859c03dc9fSBart Van Assche while (ib_poll_cq(target->recv_cq, 1, &wc) > 0) 5869c03dc9fSBart Van Assche ; /* nothing */ 5879c03dc9fSBart Van Assche while (ib_poll_cq(target->send_cq, 1, &wc) > 0) 588aef9ec39SRoland Dreier ; /* nothing */ 589aef9ec39SRoland Dreier 590536ae14eSBart Van Assche for (i = 0; i < SRP_CMD_SQ_SIZE; ++i) { 591536ae14eSBart Van Assche struct srp_request *req = &target->req_ring[i]; 592536ae14eSBart Van Assche if (req->scmnd) 593526b4caaSIshai Rabinovitz srp_reset_req(target, req); 594536ae14eSBart Van Assche } 595aef9ec39SRoland Dreier 596536ae14eSBart Van Assche INIT_LIST_HEAD(&target->free_tx); 597dcb4cb85SBart Van Assche for (i = 0; i < SRP_SQ_SIZE; ++i) 598536ae14eSBart Van Assche list_add(&target->tx_ring[i]->list, &target->free_tx); 599aef9ec39SRoland Dreier 6001033ff67SIshai Rabinovitz target->qp_in_error = 0; 601aef9ec39SRoland Dreier ret = srp_connect_target(target); 602aef9ec39SRoland Dreier if (ret) 603aef9ec39SRoland Dreier goto err; 604aef9ec39SRoland Dreier 6059709f0e0SBart Van Assche if (!srp_change_state(target, SRP_TARGET_CONNECTING, SRP_TARGET_LIVE)) 606aef9ec39SRoland Dreier ret = -EAGAIN; 607aef9ec39SRoland Dreier 608aef9ec39SRoland Dreier return ret; 609aef9ec39SRoland Dreier 610aef9ec39SRoland Dreier err: 6117aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 6127aa54bd7SDavid Dillow PFX "reconnect failed (%d), removing target port.\n", ret); 613aef9ec39SRoland Dreier 614aef9ec39SRoland Dreier /* 615aef9ec39SRoland Dreier * We couldn't reconnect, so kill our target port off. 6169709f0e0SBart Van Assche * However, we have to defer the real removal because we 6179709f0e0SBart Van Assche * are in the context of the SCSI error handler now, which 6189709f0e0SBart Van Assche * will deadlock if we call scsi_remove_host(). 6199709f0e0SBart Van Assche * 6209709f0e0SBart Van Assche * Schedule our work inside the lock to avoid a race with 6219709f0e0SBart Van Assche * the flush_scheduled_work() in srp_remove_one(). 622aef9ec39SRoland Dreier */ 623e9684678SBart Van Assche spin_lock_irq(&target->lock); 624aef9ec39SRoland Dreier if (target->state == SRP_TARGET_CONNECTING) { 625aef9ec39SRoland Dreier target->state = SRP_TARGET_DEAD; 626c4028958SDavid Howells INIT_WORK(&target->work, srp_remove_work); 627f0626710STejun Heo queue_work(ib_wq, &target->work); 628aef9ec39SRoland Dreier } 629e9684678SBart Van Assche spin_unlock_irq(&target->lock); 630aef9ec39SRoland Dreier 631aef9ec39SRoland Dreier return ret; 632aef9ec39SRoland Dreier } 633aef9ec39SRoland Dreier 634559ce8f1SIshai Rabinovitz static int srp_map_fmr(struct srp_target_port *target, struct scatterlist *scat, 635f5358a17SRoland Dreier int sg_cnt, struct srp_request *req, 636f5358a17SRoland Dreier struct srp_direct_buf *buf) 637f5358a17SRoland Dreier { 638f5358a17SRoland Dreier u64 io_addr = 0; 639f5358a17SRoland Dreier u64 *dma_pages; 640f5358a17SRoland Dreier u32 len; 641f5358a17SRoland Dreier int page_cnt; 642f5358a17SRoland Dreier int i, j; 643f5358a17SRoland Dreier int ret; 64405321937SGreg Kroah-Hartman struct srp_device *dev = target->srp_host->srp_dev; 64585507bccSRalph Campbell struct ib_device *ibdev = dev->dev; 646bb350d1dSFUJITA Tomonori struct scatterlist *sg; 647f5358a17SRoland Dreier 648f5358a17SRoland Dreier if (!dev->fmr_pool) 649f5358a17SRoland Dreier return -ENODEV; 650f5358a17SRoland Dreier 6518c4037b5SDavid Dillow if (ib_sg_dma_address(ibdev, &scat[0]) & ~dev->fmr_page_mask) 652559ce8f1SIshai Rabinovitz return -EINVAL; 653559ce8f1SIshai Rabinovitz 654f5358a17SRoland Dreier len = page_cnt = 0; 655bb350d1dSFUJITA Tomonori scsi_for_each_sg(req->scmnd, sg, sg_cnt, i) { 656bb350d1dSFUJITA Tomonori unsigned int dma_len = ib_sg_dma_len(ibdev, sg); 65785507bccSRalph Campbell 658bb350d1dSFUJITA Tomonori if (ib_sg_dma_address(ibdev, sg) & ~dev->fmr_page_mask) { 659f5358a17SRoland Dreier if (i > 0) 660f5358a17SRoland Dreier return -EINVAL; 661f5358a17SRoland Dreier else 662f5358a17SRoland Dreier ++page_cnt; 663f5358a17SRoland Dreier } 664bb350d1dSFUJITA Tomonori if ((ib_sg_dma_address(ibdev, sg) + dma_len) & 665f5358a17SRoland Dreier ~dev->fmr_page_mask) { 666f5358a17SRoland Dreier if (i < sg_cnt - 1) 667f5358a17SRoland Dreier return -EINVAL; 668f5358a17SRoland Dreier else 669f5358a17SRoland Dreier ++page_cnt; 670f5358a17SRoland Dreier } 671f5358a17SRoland Dreier 67285507bccSRalph Campbell len += dma_len; 673f5358a17SRoland Dreier } 674f5358a17SRoland Dreier 675f5358a17SRoland Dreier page_cnt += len >> dev->fmr_page_shift; 676f5358a17SRoland Dreier if (page_cnt > SRP_FMR_SIZE) 677f5358a17SRoland Dreier return -ENOMEM; 678f5358a17SRoland Dreier 679f5358a17SRoland Dreier dma_pages = kmalloc(sizeof (u64) * page_cnt, GFP_ATOMIC); 680f5358a17SRoland Dreier if (!dma_pages) 681f5358a17SRoland Dreier return -ENOMEM; 682f5358a17SRoland Dreier 683f5358a17SRoland Dreier page_cnt = 0; 684bb350d1dSFUJITA Tomonori scsi_for_each_sg(req->scmnd, sg, sg_cnt, i) { 685bb350d1dSFUJITA Tomonori unsigned int dma_len = ib_sg_dma_len(ibdev, sg); 68685507bccSRalph Campbell 68785507bccSRalph Campbell for (j = 0; j < dma_len; j += dev->fmr_page_size) 688f5358a17SRoland Dreier dma_pages[page_cnt++] = 689bb350d1dSFUJITA Tomonori (ib_sg_dma_address(ibdev, sg) & 69085507bccSRalph Campbell dev->fmr_page_mask) + j; 69185507bccSRalph Campbell } 692f5358a17SRoland Dreier 693f5358a17SRoland Dreier req->fmr = ib_fmr_pool_map_phys(dev->fmr_pool, 694adfaa888SMichael S. Tsirkin dma_pages, page_cnt, io_addr); 695f5358a17SRoland Dreier if (IS_ERR(req->fmr)) { 696f5358a17SRoland Dreier ret = PTR_ERR(req->fmr); 6976583eb3dSVu Pham req->fmr = NULL; 698f5358a17SRoland Dreier goto out; 699f5358a17SRoland Dreier } 700f5358a17SRoland Dreier 70185507bccSRalph Campbell buf->va = cpu_to_be64(ib_sg_dma_address(ibdev, &scat[0]) & 70285507bccSRalph Campbell ~dev->fmr_page_mask); 703f5358a17SRoland Dreier buf->key = cpu_to_be32(req->fmr->fmr->rkey); 704f5358a17SRoland Dreier buf->len = cpu_to_be32(len); 705f5358a17SRoland Dreier 706f5358a17SRoland Dreier ret = 0; 707f5358a17SRoland Dreier 708f5358a17SRoland Dreier out: 709f5358a17SRoland Dreier kfree(dma_pages); 710f5358a17SRoland Dreier 711f5358a17SRoland Dreier return ret; 712f5358a17SRoland Dreier } 713f5358a17SRoland Dreier 714aef9ec39SRoland Dreier static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target, 715aef9ec39SRoland Dreier struct srp_request *req) 716aef9ec39SRoland Dreier { 717cf368713SRoland Dreier struct scatterlist *scat; 718aef9ec39SRoland Dreier struct srp_cmd *cmd = req->cmd->buf; 719cf368713SRoland Dreier int len, nents, count; 720f5358a17SRoland Dreier u8 fmt = SRP_DATA_DESC_DIRECT; 72185507bccSRalph Campbell struct srp_device *dev; 72285507bccSRalph Campbell struct ib_device *ibdev; 723aef9ec39SRoland Dreier 724bb350d1dSFUJITA Tomonori if (!scsi_sglist(scmnd) || scmnd->sc_data_direction == DMA_NONE) 725aef9ec39SRoland Dreier return sizeof (struct srp_cmd); 726aef9ec39SRoland Dreier 727aef9ec39SRoland Dreier if (scmnd->sc_data_direction != DMA_FROM_DEVICE && 728aef9ec39SRoland Dreier scmnd->sc_data_direction != DMA_TO_DEVICE) { 7297aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 7307aa54bd7SDavid Dillow PFX "Unhandled data direction %d\n", 731aef9ec39SRoland Dreier scmnd->sc_data_direction); 732aef9ec39SRoland Dreier return -EINVAL; 733aef9ec39SRoland Dreier } 734aef9ec39SRoland Dreier 735bb350d1dSFUJITA Tomonori nents = scsi_sg_count(scmnd); 736bb350d1dSFUJITA Tomonori scat = scsi_sglist(scmnd); 737aef9ec39SRoland Dreier 73805321937SGreg Kroah-Hartman dev = target->srp_host->srp_dev; 73985507bccSRalph Campbell ibdev = dev->dev; 74085507bccSRalph Campbell 74185507bccSRalph Campbell count = ib_dma_map_sg(ibdev, scat, nents, scmnd->sc_data_direction); 742aef9ec39SRoland Dreier 743aef9ec39SRoland Dreier fmt = SRP_DATA_DESC_DIRECT; 744f5358a17SRoland Dreier len = sizeof (struct srp_cmd) + sizeof (struct srp_direct_buf); 745f5358a17SRoland Dreier 746f5358a17SRoland Dreier if (count == 1) { 747f5358a17SRoland Dreier /* 748f5358a17SRoland Dreier * The midlayer only generated a single gather/scatter 749f5358a17SRoland Dreier * entry, or DMA mapping coalesced everything to a 750f5358a17SRoland Dreier * single entry. So a direct descriptor along with 751f5358a17SRoland Dreier * the DMA MR suffices. 752f5358a17SRoland Dreier */ 753f5358a17SRoland Dreier struct srp_direct_buf *buf = (void *) cmd->add_data; 754aef9ec39SRoland Dreier 75585507bccSRalph Campbell buf->va = cpu_to_be64(ib_sg_dma_address(ibdev, scat)); 7569af76271SDavid Dillow buf->key = cpu_to_be32(target->rkey); 75785507bccSRalph Campbell buf->len = cpu_to_be32(ib_sg_dma_len(ibdev, scat)); 758559ce8f1SIshai Rabinovitz } else if (srp_map_fmr(target, scat, count, req, 759f5358a17SRoland Dreier (void *) cmd->add_data)) { 760f5358a17SRoland Dreier /* 761f5358a17SRoland Dreier * FMR mapping failed, and the scatterlist has more 762f5358a17SRoland Dreier * than one entry. Generate an indirect memory 763f5358a17SRoland Dreier * descriptor. 764f5358a17SRoland Dreier */ 765aef9ec39SRoland Dreier struct srp_indirect_buf *buf = (void *) cmd->add_data; 766bb350d1dSFUJITA Tomonori struct scatterlist *sg; 767aef9ec39SRoland Dreier u32 datalen = 0; 768f5358a17SRoland Dreier int i; 769aef9ec39SRoland Dreier 770aef9ec39SRoland Dreier fmt = SRP_DATA_DESC_INDIRECT; 771f5358a17SRoland Dreier len = sizeof (struct srp_cmd) + 772f5358a17SRoland Dreier sizeof (struct srp_indirect_buf) + 773f5358a17SRoland Dreier count * sizeof (struct srp_direct_buf); 774f5358a17SRoland Dreier 775bb350d1dSFUJITA Tomonori scsi_for_each_sg(scmnd, sg, count, i) { 776bb350d1dSFUJITA Tomonori unsigned int dma_len = ib_sg_dma_len(ibdev, sg); 77785507bccSRalph Campbell 778f5358a17SRoland Dreier buf->desc_list[i].va = 779bb350d1dSFUJITA Tomonori cpu_to_be64(ib_sg_dma_address(ibdev, sg)); 780f5358a17SRoland Dreier buf->desc_list[i].key = 7819af76271SDavid Dillow cpu_to_be32(target->rkey); 78285507bccSRalph Campbell buf->desc_list[i].len = cpu_to_be32(dma_len); 78385507bccSRalph Campbell datalen += dma_len; 784f5358a17SRoland Dreier } 785aef9ec39SRoland Dreier 786aef9ec39SRoland Dreier if (scmnd->sc_data_direction == DMA_TO_DEVICE) 787cf368713SRoland Dreier cmd->data_out_desc_cnt = count; 788aef9ec39SRoland Dreier else 789cf368713SRoland Dreier cmd->data_in_desc_cnt = count; 790aef9ec39SRoland Dreier 791f5358a17SRoland Dreier buf->table_desc.va = 792f5358a17SRoland Dreier cpu_to_be64(req->cmd->dma + sizeof *cmd + sizeof *buf); 793aef9ec39SRoland Dreier buf->table_desc.key = 7949af76271SDavid Dillow cpu_to_be32(target->rkey); 795aef9ec39SRoland Dreier buf->table_desc.len = 796cf368713SRoland Dreier cpu_to_be32(count * sizeof (struct srp_direct_buf)); 797aef9ec39SRoland Dreier 798aef9ec39SRoland Dreier buf->len = cpu_to_be32(datalen); 799aef9ec39SRoland Dreier } 800aef9ec39SRoland Dreier 801aef9ec39SRoland Dreier if (scmnd->sc_data_direction == DMA_TO_DEVICE) 802aef9ec39SRoland Dreier cmd->buf_fmt = fmt << 4; 803aef9ec39SRoland Dreier else 804aef9ec39SRoland Dreier cmd->buf_fmt = fmt; 805aef9ec39SRoland Dreier 806aef9ec39SRoland Dreier return len; 807aef9ec39SRoland Dreier } 808aef9ec39SRoland Dreier 80905a1d750SDavid Dillow /* 81076c75b25SBart Van Assche * Return an IU and possible credit to the free pool 81176c75b25SBart Van Assche */ 81276c75b25SBart Van Assche static void srp_put_tx_iu(struct srp_target_port *target, struct srp_iu *iu, 81376c75b25SBart Van Assche enum srp_iu_type iu_type) 81476c75b25SBart Van Assche { 81576c75b25SBart Van Assche unsigned long flags; 81676c75b25SBart Van Assche 817e9684678SBart Van Assche spin_lock_irqsave(&target->lock, flags); 81876c75b25SBart Van Assche list_add(&iu->list, &target->free_tx); 81976c75b25SBart Van Assche if (iu_type != SRP_IU_RSP) 82076c75b25SBart Van Assche ++target->req_lim; 821e9684678SBart Van Assche spin_unlock_irqrestore(&target->lock, flags); 82276c75b25SBart Van Assche } 82376c75b25SBart Van Assche 82476c75b25SBart Van Assche /* 825e9684678SBart Van Assche * Must be called with target->lock held to protect req_lim and free_tx. 826e9684678SBart Van Assche * If IU is not sent, it must be returned using srp_put_tx_iu(). 82705a1d750SDavid Dillow * 82805a1d750SDavid Dillow * Note: 82905a1d750SDavid Dillow * An upper limit for the number of allocated information units for each 83005a1d750SDavid Dillow * request type is: 83105a1d750SDavid Dillow * - SRP_IU_CMD: SRP_CMD_SQ_SIZE, since the SCSI mid-layer never queues 83205a1d750SDavid Dillow * more than Scsi_Host.can_queue requests. 83305a1d750SDavid Dillow * - SRP_IU_TSK_MGMT: SRP_TSK_MGMT_SQ_SIZE. 83405a1d750SDavid Dillow * - SRP_IU_RSP: 1, since a conforming SRP target never sends more than 83505a1d750SDavid Dillow * one unanswered SRP request to an initiator. 83605a1d750SDavid Dillow */ 83705a1d750SDavid Dillow static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target, 83805a1d750SDavid Dillow enum srp_iu_type iu_type) 83905a1d750SDavid Dillow { 84005a1d750SDavid Dillow s32 rsv = (iu_type == SRP_IU_TSK_MGMT) ? 0 : SRP_TSK_MGMT_SQ_SIZE; 84105a1d750SDavid Dillow struct srp_iu *iu; 84205a1d750SDavid Dillow 84305a1d750SDavid Dillow srp_send_completion(target->send_cq, target); 84405a1d750SDavid Dillow 845dcb4cb85SBart Van Assche if (list_empty(&target->free_tx)) 84605a1d750SDavid Dillow return NULL; 84705a1d750SDavid Dillow 84805a1d750SDavid Dillow /* Initiator responses to target requests do not consume credits */ 84976c75b25SBart Van Assche if (iu_type != SRP_IU_RSP) { 85076c75b25SBart Van Assche if (target->req_lim <= rsv) { 85105a1d750SDavid Dillow ++target->zero_req_lim; 85205a1d750SDavid Dillow return NULL; 85305a1d750SDavid Dillow } 85405a1d750SDavid Dillow 85576c75b25SBart Van Assche --target->req_lim; 85676c75b25SBart Van Assche } 85776c75b25SBart Van Assche 858dcb4cb85SBart Van Assche iu = list_first_entry(&target->free_tx, struct srp_iu, list); 85976c75b25SBart Van Assche list_del(&iu->list); 86005a1d750SDavid Dillow return iu; 86105a1d750SDavid Dillow } 86205a1d750SDavid Dillow 86376c75b25SBart Van Assche static int srp_post_send(struct srp_target_port *target, 86405a1d750SDavid Dillow struct srp_iu *iu, int len) 86505a1d750SDavid Dillow { 86605a1d750SDavid Dillow struct ib_sge list; 86705a1d750SDavid Dillow struct ib_send_wr wr, *bad_wr; 86805a1d750SDavid Dillow 86905a1d750SDavid Dillow list.addr = iu->dma; 87005a1d750SDavid Dillow list.length = len; 8719af76271SDavid Dillow list.lkey = target->lkey; 87205a1d750SDavid Dillow 87305a1d750SDavid Dillow wr.next = NULL; 874dcb4cb85SBart Van Assche wr.wr_id = (uintptr_t) iu; 87505a1d750SDavid Dillow wr.sg_list = &list; 87605a1d750SDavid Dillow wr.num_sge = 1; 87705a1d750SDavid Dillow wr.opcode = IB_WR_SEND; 87805a1d750SDavid Dillow wr.send_flags = IB_SEND_SIGNALED; 87905a1d750SDavid Dillow 88076c75b25SBart Van Assche return ib_post_send(target->qp, &wr, &bad_wr); 88105a1d750SDavid Dillow } 88205a1d750SDavid Dillow 883dcb4cb85SBart Van Assche static int srp_post_recv(struct srp_target_port *target, struct srp_iu *iu) 884c996bb47SBart Van Assche { 885c996bb47SBart Van Assche struct ib_recv_wr wr, *bad_wr; 886dcb4cb85SBart Van Assche struct ib_sge list; 887c996bb47SBart Van Assche 888c996bb47SBart Van Assche list.addr = iu->dma; 889c996bb47SBart Van Assche list.length = iu->size; 8909af76271SDavid Dillow list.lkey = target->lkey; 891c996bb47SBart Van Assche 892c996bb47SBart Van Assche wr.next = NULL; 893dcb4cb85SBart Van Assche wr.wr_id = (uintptr_t) iu; 894c996bb47SBart Van Assche wr.sg_list = &list; 895c996bb47SBart Van Assche wr.num_sge = 1; 896c996bb47SBart Van Assche 897dcb4cb85SBart Van Assche return ib_post_recv(target->qp, &wr, &bad_wr); 898c996bb47SBart Van Assche } 899c996bb47SBart Van Assche 900aef9ec39SRoland Dreier static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) 901aef9ec39SRoland Dreier { 902aef9ec39SRoland Dreier struct srp_request *req; 903aef9ec39SRoland Dreier struct scsi_cmnd *scmnd; 904aef9ec39SRoland Dreier unsigned long flags; 905aef9ec39SRoland Dreier 906aef9ec39SRoland Dreier if (unlikely(rsp->tag & SRP_TAG_TSK_MGMT)) { 907e9684678SBart Van Assche spin_lock_irqsave(&target->lock, flags); 90894a9174cSBart Van Assche target->req_lim += be32_to_cpu(rsp->req_lim_delta); 909e9684678SBart Van Assche spin_unlock_irqrestore(&target->lock, flags); 91094a9174cSBart Van Assche 911f8b6e31eSDavid Dillow target->tsk_mgmt_status = -1; 912f8b6e31eSDavid Dillow if (be32_to_cpu(rsp->resp_data_len) >= 4) 913f8b6e31eSDavid Dillow target->tsk_mgmt_status = rsp->data[3]; 914f8b6e31eSDavid Dillow complete(&target->tsk_mgmt_done); 915aef9ec39SRoland Dreier } else { 916f8b6e31eSDavid Dillow req = &target->req_ring[rsp->tag]; 917aef9ec39SRoland Dreier scmnd = req->scmnd; 918aef9ec39SRoland Dreier if (!scmnd) 9197aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 9207aa54bd7SDavid Dillow "Null scmnd for RSP w/tag %016llx\n", 921aef9ec39SRoland Dreier (unsigned long long) rsp->tag); 922aef9ec39SRoland Dreier scmnd->result = rsp->status; 923aef9ec39SRoland Dreier 924aef9ec39SRoland Dreier if (rsp->flags & SRP_RSP_FLAG_SNSVALID) { 925aef9ec39SRoland Dreier memcpy(scmnd->sense_buffer, rsp->data + 926aef9ec39SRoland Dreier be32_to_cpu(rsp->resp_data_len), 927aef9ec39SRoland Dreier min_t(int, be32_to_cpu(rsp->sense_data_len), 928aef9ec39SRoland Dreier SCSI_SENSE_BUFFERSIZE)); 929aef9ec39SRoland Dreier } 930aef9ec39SRoland Dreier 931aef9ec39SRoland Dreier if (rsp->flags & (SRP_RSP_FLAG_DOOVER | SRP_RSP_FLAG_DOUNDER)) 932bb350d1dSFUJITA Tomonori scsi_set_resid(scmnd, be32_to_cpu(rsp->data_out_res_cnt)); 933aef9ec39SRoland Dreier else if (rsp->flags & (SRP_RSP_FLAG_DIOVER | SRP_RSP_FLAG_DIUNDER)) 934bb350d1dSFUJITA Tomonori scsi_set_resid(scmnd, be32_to_cpu(rsp->data_in_res_cnt)); 935aef9ec39SRoland Dreier 93694a9174cSBart Van Assche srp_remove_req(target, req, be32_to_cpu(rsp->req_lim_delta)); 937f8b6e31eSDavid Dillow scmnd->host_scribble = NULL; 938aef9ec39SRoland Dreier scmnd->scsi_done(scmnd); 939aef9ec39SRoland Dreier } 940aef9ec39SRoland Dreier } 941aef9ec39SRoland Dreier 942bb12588aSDavid Dillow static int srp_response_common(struct srp_target_port *target, s32 req_delta, 943bb12588aSDavid Dillow void *rsp, int len) 944bb12588aSDavid Dillow { 94576c75b25SBart Van Assche struct ib_device *dev = target->srp_host->srp_dev->dev; 946bb12588aSDavid Dillow unsigned long flags; 947bb12588aSDavid Dillow struct srp_iu *iu; 94876c75b25SBart Van Assche int err; 949bb12588aSDavid Dillow 950e9684678SBart Van Assche spin_lock_irqsave(&target->lock, flags); 951bb12588aSDavid Dillow target->req_lim += req_delta; 952bb12588aSDavid Dillow iu = __srp_get_tx_iu(target, SRP_IU_RSP); 953e9684678SBart Van Assche spin_unlock_irqrestore(&target->lock, flags); 95476c75b25SBart Van Assche 955bb12588aSDavid Dillow if (!iu) { 956bb12588aSDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX 957bb12588aSDavid Dillow "no IU available to send response\n"); 95876c75b25SBart Van Assche return 1; 959bb12588aSDavid Dillow } 960bb12588aSDavid Dillow 961bb12588aSDavid Dillow ib_dma_sync_single_for_cpu(dev, iu->dma, len, DMA_TO_DEVICE); 962bb12588aSDavid Dillow memcpy(iu->buf, rsp, len); 963bb12588aSDavid Dillow ib_dma_sync_single_for_device(dev, iu->dma, len, DMA_TO_DEVICE); 964bb12588aSDavid Dillow 96576c75b25SBart Van Assche err = srp_post_send(target, iu, len); 96676c75b25SBart Van Assche if (err) { 967bb12588aSDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX 968bb12588aSDavid Dillow "unable to post response: %d\n", err); 96976c75b25SBart Van Assche srp_put_tx_iu(target, iu, SRP_IU_RSP); 97076c75b25SBart Van Assche } 971bb12588aSDavid Dillow 972bb12588aSDavid Dillow return err; 973bb12588aSDavid Dillow } 974bb12588aSDavid Dillow 975bb12588aSDavid Dillow static void srp_process_cred_req(struct srp_target_port *target, 976bb12588aSDavid Dillow struct srp_cred_req *req) 977bb12588aSDavid Dillow { 978bb12588aSDavid Dillow struct srp_cred_rsp rsp = { 979bb12588aSDavid Dillow .opcode = SRP_CRED_RSP, 980bb12588aSDavid Dillow .tag = req->tag, 981bb12588aSDavid Dillow }; 982bb12588aSDavid Dillow s32 delta = be32_to_cpu(req->req_lim_delta); 983bb12588aSDavid Dillow 984bb12588aSDavid Dillow if (srp_response_common(target, delta, &rsp, sizeof rsp)) 985bb12588aSDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX 986bb12588aSDavid Dillow "problems processing SRP_CRED_REQ\n"); 987bb12588aSDavid Dillow } 988bb12588aSDavid Dillow 989bb12588aSDavid Dillow static void srp_process_aer_req(struct srp_target_port *target, 990bb12588aSDavid Dillow struct srp_aer_req *req) 991bb12588aSDavid Dillow { 992bb12588aSDavid Dillow struct srp_aer_rsp rsp = { 993bb12588aSDavid Dillow .opcode = SRP_AER_RSP, 994bb12588aSDavid Dillow .tag = req->tag, 995bb12588aSDavid Dillow }; 996bb12588aSDavid Dillow s32 delta = be32_to_cpu(req->req_lim_delta); 997bb12588aSDavid Dillow 998bb12588aSDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX 999bb12588aSDavid Dillow "ignoring AER for LUN %llu\n", be64_to_cpu(req->lun)); 1000bb12588aSDavid Dillow 1001bb12588aSDavid Dillow if (srp_response_common(target, delta, &rsp, sizeof rsp)) 1002bb12588aSDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX 1003bb12588aSDavid Dillow "problems processing SRP_AER_REQ\n"); 1004bb12588aSDavid Dillow } 1005bb12588aSDavid Dillow 1006aef9ec39SRoland Dreier static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc) 1007aef9ec39SRoland Dreier { 1008dcb4cb85SBart Van Assche struct ib_device *dev = target->srp_host->srp_dev->dev; 1009dcb4cb85SBart Van Assche struct srp_iu *iu = (struct srp_iu *) wc->wr_id; 1010c996bb47SBart Van Assche int res; 1011aef9ec39SRoland Dreier u8 opcode; 1012aef9ec39SRoland Dreier 101385507bccSRalph Campbell ib_dma_sync_single_for_cpu(dev, iu->dma, target->max_ti_iu_len, 101485507bccSRalph Campbell DMA_FROM_DEVICE); 1015aef9ec39SRoland Dreier 1016aef9ec39SRoland Dreier opcode = *(u8 *) iu->buf; 1017aef9ec39SRoland Dreier 1018aef9ec39SRoland Dreier if (0) { 10197aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 10207aa54bd7SDavid Dillow PFX "recv completion, opcode 0x%02x\n", opcode); 10217a700811SBart Van Assche print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 8, 1, 10227a700811SBart Van Assche iu->buf, wc->byte_len, true); 1023aef9ec39SRoland Dreier } 1024aef9ec39SRoland Dreier 1025aef9ec39SRoland Dreier switch (opcode) { 1026aef9ec39SRoland Dreier case SRP_RSP: 1027aef9ec39SRoland Dreier srp_process_rsp(target, iu->buf); 1028aef9ec39SRoland Dreier break; 1029aef9ec39SRoland Dreier 1030bb12588aSDavid Dillow case SRP_CRED_REQ: 1031bb12588aSDavid Dillow srp_process_cred_req(target, iu->buf); 1032bb12588aSDavid Dillow break; 1033bb12588aSDavid Dillow 1034bb12588aSDavid Dillow case SRP_AER_REQ: 1035bb12588aSDavid Dillow srp_process_aer_req(target, iu->buf); 1036bb12588aSDavid Dillow break; 1037bb12588aSDavid Dillow 1038aef9ec39SRoland Dreier case SRP_T_LOGOUT: 1039aef9ec39SRoland Dreier /* XXX Handle target logout */ 10407aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 10417aa54bd7SDavid Dillow PFX "Got target logout request\n"); 1042aef9ec39SRoland Dreier break; 1043aef9ec39SRoland Dreier 1044aef9ec39SRoland Dreier default: 10457aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 10467aa54bd7SDavid Dillow PFX "Unhandled SRP opcode 0x%02x\n", opcode); 1047aef9ec39SRoland Dreier break; 1048aef9ec39SRoland Dreier } 1049aef9ec39SRoland Dreier 105085507bccSRalph Campbell ib_dma_sync_single_for_device(dev, iu->dma, target->max_ti_iu_len, 105185507bccSRalph Campbell DMA_FROM_DEVICE); 1052c996bb47SBart Van Assche 1053dcb4cb85SBart Van Assche res = srp_post_recv(target, iu); 1054c996bb47SBart Van Assche if (res != 0) 1055c996bb47SBart Van Assche shost_printk(KERN_ERR, target->scsi_host, 1056c996bb47SBart Van Assche PFX "Recv failed with error code %d\n", res); 1057aef9ec39SRoland Dreier } 1058aef9ec39SRoland Dreier 10599c03dc9fSBart Van Assche static void srp_recv_completion(struct ib_cq *cq, void *target_ptr) 1060aef9ec39SRoland Dreier { 1061aef9ec39SRoland Dreier struct srp_target_port *target = target_ptr; 1062aef9ec39SRoland Dreier struct ib_wc wc; 1063aef9ec39SRoland Dreier 1064aef9ec39SRoland Dreier ib_req_notify_cq(cq, IB_CQ_NEXT_COMP); 1065aef9ec39SRoland Dreier while (ib_poll_cq(cq, 1, &wc) > 0) { 1066aef9ec39SRoland Dreier if (wc.status) { 10677aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 10689c03dc9fSBart Van Assche PFX "failed receive status %d\n", 1069aef9ec39SRoland Dreier wc.status); 10701033ff67SIshai Rabinovitz target->qp_in_error = 1; 1071aef9ec39SRoland Dreier break; 1072aef9ec39SRoland Dreier } 1073aef9ec39SRoland Dreier 1074aef9ec39SRoland Dreier srp_handle_recv(target, &wc); 10759c03dc9fSBart Van Assche } 10769c03dc9fSBart Van Assche } 10779c03dc9fSBart Van Assche 10789c03dc9fSBart Van Assche static void srp_send_completion(struct ib_cq *cq, void *target_ptr) 10799c03dc9fSBart Van Assche { 10809c03dc9fSBart Van Assche struct srp_target_port *target = target_ptr; 10819c03dc9fSBart Van Assche struct ib_wc wc; 1082dcb4cb85SBart Van Assche struct srp_iu *iu; 10839c03dc9fSBart Van Assche 10849c03dc9fSBart Van Assche while (ib_poll_cq(cq, 1, &wc) > 0) { 10859c03dc9fSBart Van Assche if (wc.status) { 10869c03dc9fSBart Van Assche shost_printk(KERN_ERR, target->scsi_host, 10879c03dc9fSBart Van Assche PFX "failed send status %d\n", 10889c03dc9fSBart Van Assche wc.status); 10899c03dc9fSBart Van Assche target->qp_in_error = 1; 10909c03dc9fSBart Van Assche break; 10919c03dc9fSBart Van Assche } 10929c03dc9fSBart Van Assche 1093dcb4cb85SBart Van Assche iu = (struct srp_iu *) wc.wr_id; 1094dcb4cb85SBart Van Assche list_add(&iu->list, &target->free_tx); 1095aef9ec39SRoland Dreier } 1096aef9ec39SRoland Dreier } 1097aef9ec39SRoland Dreier 109876c75b25SBart Van Assche static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd) 1099aef9ec39SRoland Dreier { 110076c75b25SBart Van Assche struct srp_target_port *target = host_to_target(shost); 1101aef9ec39SRoland Dreier struct srp_request *req; 1102aef9ec39SRoland Dreier struct srp_iu *iu; 1103aef9ec39SRoland Dreier struct srp_cmd *cmd; 110485507bccSRalph Campbell struct ib_device *dev; 110576c75b25SBart Van Assche unsigned long flags; 1106aef9ec39SRoland Dreier int len; 1107aef9ec39SRoland Dreier 1108aef9ec39SRoland Dreier if (target->state == SRP_TARGET_CONNECTING) 1109aef9ec39SRoland Dreier goto err; 1110aef9ec39SRoland Dreier 1111aef9ec39SRoland Dreier if (target->state == SRP_TARGET_DEAD || 1112aef9ec39SRoland Dreier target->state == SRP_TARGET_REMOVED) { 1113aef9ec39SRoland Dreier scmnd->result = DID_BAD_TARGET << 16; 111476c75b25SBart Van Assche scmnd->scsi_done(scmnd); 1115aef9ec39SRoland Dreier return 0; 1116aef9ec39SRoland Dreier } 1117aef9ec39SRoland Dreier 1118e9684678SBart Van Assche spin_lock_irqsave(&target->lock, flags); 1119bb12588aSDavid Dillow iu = __srp_get_tx_iu(target, SRP_IU_CMD); 1120aef9ec39SRoland Dreier if (!iu) 1121695b8349SBart Van Assche goto err_unlock; 1122695b8349SBart Van Assche 1123695b8349SBart Van Assche req = list_first_entry(&target->free_reqs, struct srp_request, list); 1124695b8349SBart Van Assche list_del(&req->list); 1125695b8349SBart Van Assche spin_unlock_irqrestore(&target->lock, flags); 1126aef9ec39SRoland Dreier 112705321937SGreg Kroah-Hartman dev = target->srp_host->srp_dev->dev; 112885507bccSRalph Campbell ib_dma_sync_single_for_cpu(dev, iu->dma, srp_max_iu_len, 112985507bccSRalph Campbell DMA_TO_DEVICE); 1130aef9ec39SRoland Dreier 1131aef9ec39SRoland Dreier scmnd->result = 0; 1132f8b6e31eSDavid Dillow scmnd->host_scribble = (void *) req; 1133aef9ec39SRoland Dreier 1134aef9ec39SRoland Dreier cmd = iu->buf; 1135aef9ec39SRoland Dreier memset(cmd, 0, sizeof *cmd); 1136aef9ec39SRoland Dreier 1137aef9ec39SRoland Dreier cmd->opcode = SRP_CMD; 1138aef9ec39SRoland Dreier cmd->lun = cpu_to_be64((u64) scmnd->device->lun << 48); 1139d945e1dfSRoland Dreier cmd->tag = req->index; 1140aef9ec39SRoland Dreier memcpy(cmd->cdb, scmnd->cmnd, scmnd->cmd_len); 1141aef9ec39SRoland Dreier 1142aef9ec39SRoland Dreier req->scmnd = scmnd; 1143aef9ec39SRoland Dreier req->cmd = iu; 1144aef9ec39SRoland Dreier 1145aef9ec39SRoland Dreier len = srp_map_data(scmnd, target, req); 1146aef9ec39SRoland Dreier if (len < 0) { 11477aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 11487aa54bd7SDavid Dillow PFX "Failed to map data\n"); 114976c75b25SBart Van Assche goto err_iu; 1150aef9ec39SRoland Dreier } 1151aef9ec39SRoland Dreier 115285507bccSRalph Campbell ib_dma_sync_single_for_device(dev, iu->dma, srp_max_iu_len, 115385507bccSRalph Campbell DMA_TO_DEVICE); 1154aef9ec39SRoland Dreier 115576c75b25SBart Van Assche if (srp_post_send(target, iu, len)) { 11567aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX "Send failed\n"); 1157aef9ec39SRoland Dreier goto err_unmap; 1158aef9ec39SRoland Dreier } 1159aef9ec39SRoland Dreier 1160aef9ec39SRoland Dreier return 0; 1161aef9ec39SRoland Dreier 1162aef9ec39SRoland Dreier err_unmap: 1163aef9ec39SRoland Dreier srp_unmap_data(scmnd, target, req); 1164aef9ec39SRoland Dreier 116576c75b25SBart Van Assche err_iu: 116676c75b25SBart Van Assche srp_put_tx_iu(target, iu, SRP_IU_CMD); 116776c75b25SBart Van Assche 1168e9684678SBart Van Assche spin_lock_irqsave(&target->lock, flags); 116976c75b25SBart Van Assche list_add(&req->list, &target->free_reqs); 1170695b8349SBart Van Assche 1171695b8349SBart Van Assche err_unlock: 1172e9684678SBart Van Assche spin_unlock_irqrestore(&target->lock, flags); 117376c75b25SBart Van Assche 1174aef9ec39SRoland Dreier err: 1175aef9ec39SRoland Dreier return SCSI_MLQUEUE_HOST_BUSY; 1176aef9ec39SRoland Dreier } 1177aef9ec39SRoland Dreier 1178aef9ec39SRoland Dreier static int srp_alloc_iu_bufs(struct srp_target_port *target) 1179aef9ec39SRoland Dreier { 1180aef9ec39SRoland Dreier int i; 1181aef9ec39SRoland Dreier 1182aef9ec39SRoland Dreier for (i = 0; i < SRP_RQ_SIZE; ++i) { 1183aef9ec39SRoland Dreier target->rx_ring[i] = srp_alloc_iu(target->srp_host, 1184aef9ec39SRoland Dreier target->max_ti_iu_len, 1185aef9ec39SRoland Dreier GFP_KERNEL, DMA_FROM_DEVICE); 1186aef9ec39SRoland Dreier if (!target->rx_ring[i]) 1187aef9ec39SRoland Dreier goto err; 1188aef9ec39SRoland Dreier } 1189aef9ec39SRoland Dreier 1190dd5e6e38SBart Van Assche for (i = 0; i < SRP_SQ_SIZE; ++i) { 1191aef9ec39SRoland Dreier target->tx_ring[i] = srp_alloc_iu(target->srp_host, 119274b0a15bSVu Pham srp_max_iu_len, 1193aef9ec39SRoland Dreier GFP_KERNEL, DMA_TO_DEVICE); 1194aef9ec39SRoland Dreier if (!target->tx_ring[i]) 1195aef9ec39SRoland Dreier goto err; 1196dcb4cb85SBart Van Assche 1197dcb4cb85SBart Van Assche list_add(&target->tx_ring[i]->list, &target->free_tx); 1198aef9ec39SRoland Dreier } 1199aef9ec39SRoland Dreier 1200aef9ec39SRoland Dreier return 0; 1201aef9ec39SRoland Dreier 1202aef9ec39SRoland Dreier err: 1203aef9ec39SRoland Dreier for (i = 0; i < SRP_RQ_SIZE; ++i) { 1204aef9ec39SRoland Dreier srp_free_iu(target->srp_host, target->rx_ring[i]); 1205aef9ec39SRoland Dreier target->rx_ring[i] = NULL; 1206aef9ec39SRoland Dreier } 1207aef9ec39SRoland Dreier 1208dd5e6e38SBart Van Assche for (i = 0; i < SRP_SQ_SIZE; ++i) { 1209aef9ec39SRoland Dreier srp_free_iu(target->srp_host, target->tx_ring[i]); 1210aef9ec39SRoland Dreier target->tx_ring[i] = NULL; 1211aef9ec39SRoland Dreier } 1212aef9ec39SRoland Dreier 1213aef9ec39SRoland Dreier return -ENOMEM; 1214aef9ec39SRoland Dreier } 1215aef9ec39SRoland Dreier 1216*961e0be8SDavid Dillow static void srp_cm_rep_handler(struct ib_cm_id *cm_id, 1217*961e0be8SDavid Dillow struct srp_login_rsp *lrsp, 1218*961e0be8SDavid Dillow struct srp_target_port *target) 1219*961e0be8SDavid Dillow { 1220*961e0be8SDavid Dillow struct ib_qp_attr *qp_attr = NULL; 1221*961e0be8SDavid Dillow int attr_mask = 0; 1222*961e0be8SDavid Dillow int ret; 1223*961e0be8SDavid Dillow int i; 1224*961e0be8SDavid Dillow 1225*961e0be8SDavid Dillow if (lrsp->opcode == SRP_LOGIN_RSP) { 1226*961e0be8SDavid Dillow target->max_ti_iu_len = be32_to_cpu(lrsp->max_ti_iu_len); 1227*961e0be8SDavid Dillow target->req_lim = be32_to_cpu(lrsp->req_lim_delta); 1228*961e0be8SDavid Dillow 1229*961e0be8SDavid Dillow /* 1230*961e0be8SDavid Dillow * Reserve credits for task management so we don't 1231*961e0be8SDavid Dillow * bounce requests back to the SCSI mid-layer. 1232*961e0be8SDavid Dillow */ 1233*961e0be8SDavid Dillow target->scsi_host->can_queue 1234*961e0be8SDavid Dillow = min(target->req_lim - SRP_TSK_MGMT_SQ_SIZE, 1235*961e0be8SDavid Dillow target->scsi_host->can_queue); 1236*961e0be8SDavid Dillow } else { 1237*961e0be8SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 1238*961e0be8SDavid Dillow PFX "Unhandled RSP opcode %#x\n", lrsp->opcode); 1239*961e0be8SDavid Dillow ret = -ECONNRESET; 1240*961e0be8SDavid Dillow goto error; 1241*961e0be8SDavid Dillow } 1242*961e0be8SDavid Dillow 1243*961e0be8SDavid Dillow if (!target->rx_ring[0]) { 1244*961e0be8SDavid Dillow ret = srp_alloc_iu_bufs(target); 1245*961e0be8SDavid Dillow if (ret) 1246*961e0be8SDavid Dillow goto error; 1247*961e0be8SDavid Dillow } 1248*961e0be8SDavid Dillow 1249*961e0be8SDavid Dillow ret = -ENOMEM; 1250*961e0be8SDavid Dillow qp_attr = kmalloc(sizeof *qp_attr, GFP_KERNEL); 1251*961e0be8SDavid Dillow if (!qp_attr) 1252*961e0be8SDavid Dillow goto error; 1253*961e0be8SDavid Dillow 1254*961e0be8SDavid Dillow qp_attr->qp_state = IB_QPS_RTR; 1255*961e0be8SDavid Dillow ret = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask); 1256*961e0be8SDavid Dillow if (ret) 1257*961e0be8SDavid Dillow goto error_free; 1258*961e0be8SDavid Dillow 1259*961e0be8SDavid Dillow ret = ib_modify_qp(target->qp, qp_attr, attr_mask); 1260*961e0be8SDavid Dillow if (ret) 1261*961e0be8SDavid Dillow goto error_free; 1262*961e0be8SDavid Dillow 1263*961e0be8SDavid Dillow for (i = 0; i < SRP_RQ_SIZE; i++) { 1264*961e0be8SDavid Dillow struct srp_iu *iu = target->rx_ring[i]; 1265*961e0be8SDavid Dillow ret = srp_post_recv(target, iu); 1266*961e0be8SDavid Dillow if (ret) 1267*961e0be8SDavid Dillow goto error_free; 1268*961e0be8SDavid Dillow } 1269*961e0be8SDavid Dillow 1270*961e0be8SDavid Dillow qp_attr->qp_state = IB_QPS_RTS; 1271*961e0be8SDavid Dillow ret = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask); 1272*961e0be8SDavid Dillow if (ret) 1273*961e0be8SDavid Dillow goto error_free; 1274*961e0be8SDavid Dillow 1275*961e0be8SDavid Dillow ret = ib_modify_qp(target->qp, qp_attr, attr_mask); 1276*961e0be8SDavid Dillow if (ret) 1277*961e0be8SDavid Dillow goto error_free; 1278*961e0be8SDavid Dillow 1279*961e0be8SDavid Dillow ret = ib_send_cm_rtu(cm_id, NULL, 0); 1280*961e0be8SDavid Dillow 1281*961e0be8SDavid Dillow error_free: 1282*961e0be8SDavid Dillow kfree(qp_attr); 1283*961e0be8SDavid Dillow 1284*961e0be8SDavid Dillow error: 1285*961e0be8SDavid Dillow target->status = ret; 1286*961e0be8SDavid Dillow } 1287*961e0be8SDavid Dillow 1288aef9ec39SRoland Dreier static void srp_cm_rej_handler(struct ib_cm_id *cm_id, 1289aef9ec39SRoland Dreier struct ib_cm_event *event, 1290aef9ec39SRoland Dreier struct srp_target_port *target) 1291aef9ec39SRoland Dreier { 12927aa54bd7SDavid Dillow struct Scsi_Host *shost = target->scsi_host; 1293aef9ec39SRoland Dreier struct ib_class_port_info *cpi; 1294aef9ec39SRoland Dreier int opcode; 1295aef9ec39SRoland Dreier 1296aef9ec39SRoland Dreier switch (event->param.rej_rcvd.reason) { 1297aef9ec39SRoland Dreier case IB_CM_REJ_PORT_CM_REDIRECT: 1298aef9ec39SRoland Dreier cpi = event->param.rej_rcvd.ari; 1299aef9ec39SRoland Dreier target->path.dlid = cpi->redirect_lid; 1300aef9ec39SRoland Dreier target->path.pkey = cpi->redirect_pkey; 1301aef9ec39SRoland Dreier cm_id->remote_cm_qpn = be32_to_cpu(cpi->redirect_qp) & 0x00ffffff; 1302aef9ec39SRoland Dreier memcpy(target->path.dgid.raw, cpi->redirect_gid, 16); 1303aef9ec39SRoland Dreier 1304aef9ec39SRoland Dreier target->status = target->path.dlid ? 1305aef9ec39SRoland Dreier SRP_DLID_REDIRECT : SRP_PORT_REDIRECT; 1306aef9ec39SRoland Dreier break; 1307aef9ec39SRoland Dreier 1308aef9ec39SRoland Dreier case IB_CM_REJ_PORT_REDIRECT: 13095d7cbfd6SRoland Dreier if (srp_target_is_topspin(target)) { 1310aef9ec39SRoland Dreier /* 1311aef9ec39SRoland Dreier * Topspin/Cisco SRP gateways incorrectly send 1312aef9ec39SRoland Dreier * reject reason code 25 when they mean 24 1313aef9ec39SRoland Dreier * (port redirect). 1314aef9ec39SRoland Dreier */ 1315aef9ec39SRoland Dreier memcpy(target->path.dgid.raw, 1316aef9ec39SRoland Dreier event->param.rej_rcvd.ari, 16); 1317aef9ec39SRoland Dreier 13187aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, shost, 13197aa54bd7SDavid Dillow PFX "Topspin/Cisco redirect to target port GID %016llx%016llx\n", 1320aef9ec39SRoland Dreier (unsigned long long) be64_to_cpu(target->path.dgid.global.subnet_prefix), 1321aef9ec39SRoland Dreier (unsigned long long) be64_to_cpu(target->path.dgid.global.interface_id)); 1322aef9ec39SRoland Dreier 1323aef9ec39SRoland Dreier target->status = SRP_PORT_REDIRECT; 1324aef9ec39SRoland Dreier } else { 13257aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, 13267aa54bd7SDavid Dillow " REJ reason: IB_CM_REJ_PORT_REDIRECT\n"); 1327aef9ec39SRoland Dreier target->status = -ECONNRESET; 1328aef9ec39SRoland Dreier } 1329aef9ec39SRoland Dreier break; 1330aef9ec39SRoland Dreier 1331aef9ec39SRoland Dreier case IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID: 13327aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, 13337aa54bd7SDavid Dillow " REJ reason: IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID\n"); 1334aef9ec39SRoland Dreier target->status = -ECONNRESET; 1335aef9ec39SRoland Dreier break; 1336aef9ec39SRoland Dreier 1337aef9ec39SRoland Dreier case IB_CM_REJ_CONSUMER_DEFINED: 1338aef9ec39SRoland Dreier opcode = *(u8 *) event->private_data; 1339aef9ec39SRoland Dreier if (opcode == SRP_LOGIN_REJ) { 1340aef9ec39SRoland Dreier struct srp_login_rej *rej = event->private_data; 1341aef9ec39SRoland Dreier u32 reason = be32_to_cpu(rej->reason); 1342aef9ec39SRoland Dreier 1343aef9ec39SRoland Dreier if (reason == SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE) 13447aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, 13457aa54bd7SDavid Dillow PFX "SRP_LOGIN_REJ: requested max_it_iu_len too large\n"); 1346aef9ec39SRoland Dreier else 13477aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, 13487aa54bd7SDavid Dillow PFX "SRP LOGIN REJECTED, reason 0x%08x\n", reason); 1349aef9ec39SRoland Dreier } else 13507aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, 13517aa54bd7SDavid Dillow " REJ reason: IB_CM_REJ_CONSUMER_DEFINED," 1352aef9ec39SRoland Dreier " opcode 0x%02x\n", opcode); 1353aef9ec39SRoland Dreier target->status = -ECONNRESET; 1354aef9ec39SRoland Dreier break; 1355aef9ec39SRoland Dreier 13569fe4bcf4SDavid Dillow case IB_CM_REJ_STALE_CONN: 13579fe4bcf4SDavid Dillow shost_printk(KERN_WARNING, shost, " REJ reason: stale connection\n"); 13589fe4bcf4SDavid Dillow target->status = SRP_STALE_CONN; 13599fe4bcf4SDavid Dillow break; 13609fe4bcf4SDavid Dillow 1361aef9ec39SRoland Dreier default: 13627aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, " REJ reason 0x%x\n", 1363aef9ec39SRoland Dreier event->param.rej_rcvd.reason); 1364aef9ec39SRoland Dreier target->status = -ECONNRESET; 1365aef9ec39SRoland Dreier } 1366aef9ec39SRoland Dreier } 1367aef9ec39SRoland Dreier 1368aef9ec39SRoland Dreier static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) 1369aef9ec39SRoland Dreier { 1370aef9ec39SRoland Dreier struct srp_target_port *target = cm_id->context; 1371aef9ec39SRoland Dreier int comp = 0; 1372aef9ec39SRoland Dreier 1373aef9ec39SRoland Dreier switch (event->event) { 1374aef9ec39SRoland Dreier case IB_CM_REQ_ERROR: 13757aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, target->scsi_host, 13767aa54bd7SDavid Dillow PFX "Sending CM REQ failed\n"); 1377aef9ec39SRoland Dreier comp = 1; 1378aef9ec39SRoland Dreier target->status = -ECONNRESET; 1379aef9ec39SRoland Dreier break; 1380aef9ec39SRoland Dreier 1381aef9ec39SRoland Dreier case IB_CM_REP_RECEIVED: 1382aef9ec39SRoland Dreier comp = 1; 1383*961e0be8SDavid Dillow srp_cm_rep_handler(cm_id, event->private_data, target); 1384aef9ec39SRoland Dreier break; 1385aef9ec39SRoland Dreier 1386aef9ec39SRoland Dreier case IB_CM_REJ_RECEIVED: 13877aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, target->scsi_host, PFX "REJ received\n"); 1388aef9ec39SRoland Dreier comp = 1; 1389aef9ec39SRoland Dreier 1390aef9ec39SRoland Dreier srp_cm_rej_handler(cm_id, event, target); 1391aef9ec39SRoland Dreier break; 1392aef9ec39SRoland Dreier 1393b7ac4ab4SIshai Rabinovitz case IB_CM_DREQ_RECEIVED: 13947aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 13957aa54bd7SDavid Dillow PFX "DREQ received - connection closed\n"); 1396b7ac4ab4SIshai Rabinovitz if (ib_send_cm_drep(cm_id, NULL, 0)) 13977aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 13987aa54bd7SDavid Dillow PFX "Sending CM DREP failed\n"); 1399aef9ec39SRoland Dreier break; 1400aef9ec39SRoland Dreier 1401aef9ec39SRoland Dreier case IB_CM_TIMEWAIT_EXIT: 14027aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 14037aa54bd7SDavid Dillow PFX "connection closed\n"); 1404aef9ec39SRoland Dreier 1405aef9ec39SRoland Dreier comp = 1; 1406aef9ec39SRoland Dreier target->status = 0; 1407aef9ec39SRoland Dreier break; 1408aef9ec39SRoland Dreier 1409b7ac4ab4SIshai Rabinovitz case IB_CM_MRA_RECEIVED: 1410b7ac4ab4SIshai Rabinovitz case IB_CM_DREQ_ERROR: 1411b7ac4ab4SIshai Rabinovitz case IB_CM_DREP_RECEIVED: 1412b7ac4ab4SIshai Rabinovitz break; 1413b7ac4ab4SIshai Rabinovitz 1414aef9ec39SRoland Dreier default: 14157aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 14167aa54bd7SDavid Dillow PFX "Unhandled CM event %d\n", event->event); 1417aef9ec39SRoland Dreier break; 1418aef9ec39SRoland Dreier } 1419aef9ec39SRoland Dreier 1420aef9ec39SRoland Dreier if (comp) 1421aef9ec39SRoland Dreier complete(&target->done); 1422aef9ec39SRoland Dreier 1423aef9ec39SRoland Dreier return 0; 1424aef9ec39SRoland Dreier } 1425aef9ec39SRoland Dreier 1426d945e1dfSRoland Dreier static int srp_send_tsk_mgmt(struct srp_target_port *target, 1427f8b6e31eSDavid Dillow u64 req_tag, unsigned int lun, u8 func) 1428aef9ec39SRoland Dreier { 142919081f31SDavid Dillow struct ib_device *dev = target->srp_host->srp_dev->dev; 1430aef9ec39SRoland Dreier struct srp_iu *iu; 1431aef9ec39SRoland Dreier struct srp_tsk_mgmt *tsk_mgmt; 1432aef9ec39SRoland Dreier 14331285b3a0SRoland Dreier if (target->state == SRP_TARGET_DEAD || 1434f8b6e31eSDavid Dillow target->state == SRP_TARGET_REMOVED) 143576c75b25SBart Van Assche return -1; 14361285b3a0SRoland Dreier 1437f8b6e31eSDavid Dillow init_completion(&target->tsk_mgmt_done); 1438aef9ec39SRoland Dreier 1439e9684678SBart Van Assche spin_lock_irq(&target->lock); 1440bb12588aSDavid Dillow iu = __srp_get_tx_iu(target, SRP_IU_TSK_MGMT); 1441e9684678SBart Van Assche spin_unlock_irq(&target->lock); 144276c75b25SBart Van Assche 1443aef9ec39SRoland Dreier if (!iu) 144476c75b25SBart Van Assche return -1; 1445aef9ec39SRoland Dreier 144619081f31SDavid Dillow ib_dma_sync_single_for_cpu(dev, iu->dma, sizeof *tsk_mgmt, 144719081f31SDavid Dillow DMA_TO_DEVICE); 1448aef9ec39SRoland Dreier tsk_mgmt = iu->buf; 1449aef9ec39SRoland Dreier memset(tsk_mgmt, 0, sizeof *tsk_mgmt); 1450aef9ec39SRoland Dreier 1451aef9ec39SRoland Dreier tsk_mgmt->opcode = SRP_TSK_MGMT; 1452f8b6e31eSDavid Dillow tsk_mgmt->lun = cpu_to_be64((u64) lun << 48); 1453f8b6e31eSDavid Dillow tsk_mgmt->tag = req_tag | SRP_TAG_TSK_MGMT; 1454aef9ec39SRoland Dreier tsk_mgmt->tsk_mgmt_func = func; 1455f8b6e31eSDavid Dillow tsk_mgmt->task_tag = req_tag; 1456aef9ec39SRoland Dreier 145719081f31SDavid Dillow ib_dma_sync_single_for_device(dev, iu->dma, sizeof *tsk_mgmt, 145819081f31SDavid Dillow DMA_TO_DEVICE); 145976c75b25SBart Van Assche if (srp_post_send(target, iu, sizeof *tsk_mgmt)) { 146076c75b25SBart Van Assche srp_put_tx_iu(target, iu, SRP_IU_TSK_MGMT); 146176c75b25SBart Van Assche return -1; 146276c75b25SBart Van Assche } 1463d945e1dfSRoland Dreier 1464f8b6e31eSDavid Dillow if (!wait_for_completion_timeout(&target->tsk_mgmt_done, 1465aef9ec39SRoland Dreier msecs_to_jiffies(SRP_ABORT_TIMEOUT_MS))) 1466d945e1dfSRoland Dreier return -1; 1467aef9ec39SRoland Dreier 1468d945e1dfSRoland Dreier return 0; 1469d945e1dfSRoland Dreier } 1470d945e1dfSRoland Dreier 1471aef9ec39SRoland Dreier static int srp_abort(struct scsi_cmnd *scmnd) 1472aef9ec39SRoland Dreier { 1473d945e1dfSRoland Dreier struct srp_target_port *target = host_to_target(scmnd->device->host); 1474f8b6e31eSDavid Dillow struct srp_request *req = (struct srp_request *) scmnd->host_scribble; 1475d945e1dfSRoland Dreier int ret = SUCCESS; 1476d945e1dfSRoland Dreier 14777aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n"); 1478aef9ec39SRoland Dreier 1479f8b6e31eSDavid Dillow if (!req || target->qp_in_error) 14801033ff67SIshai Rabinovitz return FAILED; 1481f8b6e31eSDavid Dillow if (srp_send_tsk_mgmt(target, req->index, scmnd->device->lun, 1482f8b6e31eSDavid Dillow SRP_TSK_ABORT_TASK)) 1483d945e1dfSRoland Dreier return FAILED; 1484d945e1dfSRoland Dreier 1485f8b6e31eSDavid Dillow if (req->scmnd) { 1486f8b6e31eSDavid Dillow if (!target->tsk_mgmt_status) { 148794a9174cSBart Van Assche srp_remove_req(target, req, 0); 1488d945e1dfSRoland Dreier scmnd->result = DID_ABORT << 16; 1489d945e1dfSRoland Dreier } else 1490d945e1dfSRoland Dreier ret = FAILED; 1491f8b6e31eSDavid Dillow } 1492d945e1dfSRoland Dreier 1493d945e1dfSRoland Dreier return ret; 1494aef9ec39SRoland Dreier } 1495aef9ec39SRoland Dreier 1496aef9ec39SRoland Dreier static int srp_reset_device(struct scsi_cmnd *scmnd) 1497aef9ec39SRoland Dreier { 1498d945e1dfSRoland Dreier struct srp_target_port *target = host_to_target(scmnd->device->host); 1499536ae14eSBart Van Assche int i; 1500d945e1dfSRoland Dreier 15017aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, "SRP reset_device called\n"); 1502aef9ec39SRoland Dreier 15031033ff67SIshai Rabinovitz if (target->qp_in_error) 15041033ff67SIshai Rabinovitz return FAILED; 1505f8b6e31eSDavid Dillow if (srp_send_tsk_mgmt(target, SRP_TAG_NO_REQ, scmnd->device->lun, 1506f8b6e31eSDavid Dillow SRP_TSK_LUN_RESET)) 1507d945e1dfSRoland Dreier return FAILED; 1508f8b6e31eSDavid Dillow if (target->tsk_mgmt_status) 1509d945e1dfSRoland Dreier return FAILED; 1510d945e1dfSRoland Dreier 1511536ae14eSBart Van Assche for (i = 0; i < SRP_CMD_SQ_SIZE; ++i) { 1512536ae14eSBart Van Assche struct srp_request *req = &target->req_ring[i]; 1513f8b6e31eSDavid Dillow if (req->scmnd && req->scmnd->device == scmnd->device) 1514526b4caaSIshai Rabinovitz srp_reset_req(target, req); 1515536ae14eSBart Van Assche } 1516d945e1dfSRoland Dreier 1517d945e1dfSRoland Dreier return SUCCESS; 1518aef9ec39SRoland Dreier } 1519aef9ec39SRoland Dreier 1520aef9ec39SRoland Dreier static int srp_reset_host(struct scsi_cmnd *scmnd) 1521aef9ec39SRoland Dreier { 1522aef9ec39SRoland Dreier struct srp_target_port *target = host_to_target(scmnd->device->host); 1523aef9ec39SRoland Dreier int ret = FAILED; 1524aef9ec39SRoland Dreier 15257aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX "SRP reset_host called\n"); 1526aef9ec39SRoland Dreier 1527aef9ec39SRoland Dreier if (!srp_reconnect_target(target)) 1528aef9ec39SRoland Dreier ret = SUCCESS; 1529aef9ec39SRoland Dreier 1530aef9ec39SRoland Dreier return ret; 1531aef9ec39SRoland Dreier } 1532aef9ec39SRoland Dreier 1533ee959b00STony Jones static ssize_t show_id_ext(struct device *dev, struct device_attribute *attr, 1534ee959b00STony Jones char *buf) 15356ecb0c84SRoland Dreier { 1536ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 15376ecb0c84SRoland Dreier 15386ecb0c84SRoland Dreier if (target->state == SRP_TARGET_DEAD || 15396ecb0c84SRoland Dreier target->state == SRP_TARGET_REMOVED) 15406ecb0c84SRoland Dreier return -ENODEV; 15416ecb0c84SRoland Dreier 15426ecb0c84SRoland Dreier return sprintf(buf, "0x%016llx\n", 15436ecb0c84SRoland Dreier (unsigned long long) be64_to_cpu(target->id_ext)); 15446ecb0c84SRoland Dreier } 15456ecb0c84SRoland Dreier 1546ee959b00STony Jones static ssize_t show_ioc_guid(struct device *dev, struct device_attribute *attr, 1547ee959b00STony Jones char *buf) 15486ecb0c84SRoland Dreier { 1549ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 15506ecb0c84SRoland Dreier 15516ecb0c84SRoland Dreier if (target->state == SRP_TARGET_DEAD || 15526ecb0c84SRoland Dreier target->state == SRP_TARGET_REMOVED) 15536ecb0c84SRoland Dreier return -ENODEV; 15546ecb0c84SRoland Dreier 15556ecb0c84SRoland Dreier return sprintf(buf, "0x%016llx\n", 15566ecb0c84SRoland Dreier (unsigned long long) be64_to_cpu(target->ioc_guid)); 15576ecb0c84SRoland Dreier } 15586ecb0c84SRoland Dreier 1559ee959b00STony Jones static ssize_t show_service_id(struct device *dev, 1560ee959b00STony Jones struct device_attribute *attr, char *buf) 15616ecb0c84SRoland Dreier { 1562ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 15636ecb0c84SRoland Dreier 15646ecb0c84SRoland Dreier if (target->state == SRP_TARGET_DEAD || 15656ecb0c84SRoland Dreier target->state == SRP_TARGET_REMOVED) 15666ecb0c84SRoland Dreier return -ENODEV; 15676ecb0c84SRoland Dreier 15686ecb0c84SRoland Dreier return sprintf(buf, "0x%016llx\n", 15696ecb0c84SRoland Dreier (unsigned long long) be64_to_cpu(target->service_id)); 15706ecb0c84SRoland Dreier } 15716ecb0c84SRoland Dreier 1572ee959b00STony Jones static ssize_t show_pkey(struct device *dev, struct device_attribute *attr, 1573ee959b00STony Jones char *buf) 15746ecb0c84SRoland Dreier { 1575ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 15766ecb0c84SRoland Dreier 15776ecb0c84SRoland Dreier if (target->state == SRP_TARGET_DEAD || 15786ecb0c84SRoland Dreier target->state == SRP_TARGET_REMOVED) 15796ecb0c84SRoland Dreier return -ENODEV; 15806ecb0c84SRoland Dreier 15816ecb0c84SRoland Dreier return sprintf(buf, "0x%04x\n", be16_to_cpu(target->path.pkey)); 15826ecb0c84SRoland Dreier } 15836ecb0c84SRoland Dreier 1584ee959b00STony Jones static ssize_t show_dgid(struct device *dev, struct device_attribute *attr, 1585ee959b00STony Jones char *buf) 15866ecb0c84SRoland Dreier { 1587ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 15886ecb0c84SRoland Dreier 15896ecb0c84SRoland Dreier if (target->state == SRP_TARGET_DEAD || 15906ecb0c84SRoland Dreier target->state == SRP_TARGET_REMOVED) 15916ecb0c84SRoland Dreier return -ENODEV; 15926ecb0c84SRoland Dreier 15935b095d98SHarvey Harrison return sprintf(buf, "%pI6\n", target->path.dgid.raw); 15946ecb0c84SRoland Dreier } 15956ecb0c84SRoland Dreier 1596ee959b00STony Jones static ssize_t show_orig_dgid(struct device *dev, 1597ee959b00STony Jones struct device_attribute *attr, char *buf) 15983633b3d0SIshai Rabinovitz { 1599ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 16003633b3d0SIshai Rabinovitz 16013633b3d0SIshai Rabinovitz if (target->state == SRP_TARGET_DEAD || 16023633b3d0SIshai Rabinovitz target->state == SRP_TARGET_REMOVED) 16033633b3d0SIshai Rabinovitz return -ENODEV; 16043633b3d0SIshai Rabinovitz 16055b095d98SHarvey Harrison return sprintf(buf, "%pI6\n", target->orig_dgid); 16063633b3d0SIshai Rabinovitz } 16073633b3d0SIshai Rabinovitz 160889de7486SBart Van Assche static ssize_t show_req_lim(struct device *dev, 160989de7486SBart Van Assche struct device_attribute *attr, char *buf) 161089de7486SBart Van Assche { 161189de7486SBart Van Assche struct srp_target_port *target = host_to_target(class_to_shost(dev)); 161289de7486SBart Van Assche 161389de7486SBart Van Assche if (target->state == SRP_TARGET_DEAD || 161489de7486SBart Van Assche target->state == SRP_TARGET_REMOVED) 161589de7486SBart Van Assche return -ENODEV; 161689de7486SBart Van Assche 161789de7486SBart Van Assche return sprintf(buf, "%d\n", target->req_lim); 161889de7486SBart Van Assche } 161989de7486SBart Van Assche 1620ee959b00STony Jones static ssize_t show_zero_req_lim(struct device *dev, 1621ee959b00STony Jones struct device_attribute *attr, char *buf) 16226bfa24faSRoland Dreier { 1623ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 16246bfa24faSRoland Dreier 16256bfa24faSRoland Dreier if (target->state == SRP_TARGET_DEAD || 16266bfa24faSRoland Dreier target->state == SRP_TARGET_REMOVED) 16276bfa24faSRoland Dreier return -ENODEV; 16286bfa24faSRoland Dreier 16296bfa24faSRoland Dreier return sprintf(buf, "%d\n", target->zero_req_lim); 16306bfa24faSRoland Dreier } 16316bfa24faSRoland Dreier 1632ee959b00STony Jones static ssize_t show_local_ib_port(struct device *dev, 1633ee959b00STony Jones struct device_attribute *attr, char *buf) 1634ded7f1a1SIshai Rabinovitz { 1635ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 1636ded7f1a1SIshai Rabinovitz 1637ded7f1a1SIshai Rabinovitz return sprintf(buf, "%d\n", target->srp_host->port); 1638ded7f1a1SIshai Rabinovitz } 1639ded7f1a1SIshai Rabinovitz 1640ee959b00STony Jones static ssize_t show_local_ib_device(struct device *dev, 1641ee959b00STony Jones struct device_attribute *attr, char *buf) 1642ded7f1a1SIshai Rabinovitz { 1643ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 1644ded7f1a1SIshai Rabinovitz 164505321937SGreg Kroah-Hartman return sprintf(buf, "%s\n", target->srp_host->srp_dev->dev->name); 1646ded7f1a1SIshai Rabinovitz } 1647ded7f1a1SIshai Rabinovitz 1648ee959b00STony Jones static DEVICE_ATTR(id_ext, S_IRUGO, show_id_ext, NULL); 1649ee959b00STony Jones static DEVICE_ATTR(ioc_guid, S_IRUGO, show_ioc_guid, NULL); 1650ee959b00STony Jones static DEVICE_ATTR(service_id, S_IRUGO, show_service_id, NULL); 1651ee959b00STony Jones static DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL); 1652ee959b00STony Jones static DEVICE_ATTR(dgid, S_IRUGO, show_dgid, NULL); 1653ee959b00STony Jones static DEVICE_ATTR(orig_dgid, S_IRUGO, show_orig_dgid, NULL); 165489de7486SBart Van Assche static DEVICE_ATTR(req_lim, S_IRUGO, show_req_lim, NULL); 1655ee959b00STony Jones static DEVICE_ATTR(zero_req_lim, S_IRUGO, show_zero_req_lim, NULL); 1656ee959b00STony Jones static DEVICE_ATTR(local_ib_port, S_IRUGO, show_local_ib_port, NULL); 1657ee959b00STony Jones static DEVICE_ATTR(local_ib_device, S_IRUGO, show_local_ib_device, NULL); 16586ecb0c84SRoland Dreier 1659ee959b00STony Jones static struct device_attribute *srp_host_attrs[] = { 1660ee959b00STony Jones &dev_attr_id_ext, 1661ee959b00STony Jones &dev_attr_ioc_guid, 1662ee959b00STony Jones &dev_attr_service_id, 1663ee959b00STony Jones &dev_attr_pkey, 1664ee959b00STony Jones &dev_attr_dgid, 1665ee959b00STony Jones &dev_attr_orig_dgid, 166689de7486SBart Van Assche &dev_attr_req_lim, 1667ee959b00STony Jones &dev_attr_zero_req_lim, 1668ee959b00STony Jones &dev_attr_local_ib_port, 1669ee959b00STony Jones &dev_attr_local_ib_device, 16706ecb0c84SRoland Dreier NULL 16716ecb0c84SRoland Dreier }; 16726ecb0c84SRoland Dreier 1673aef9ec39SRoland Dreier static struct scsi_host_template srp_template = { 1674aef9ec39SRoland Dreier .module = THIS_MODULE, 1675b7f008fdSRoland Dreier .name = "InfiniBand SRP initiator", 1676b7f008fdSRoland Dreier .proc_name = DRV_NAME, 1677aef9ec39SRoland Dreier .info = srp_target_info, 1678aef9ec39SRoland Dreier .queuecommand = srp_queuecommand, 1679aef9ec39SRoland Dreier .eh_abort_handler = srp_abort, 1680aef9ec39SRoland Dreier .eh_device_reset_handler = srp_reset_device, 1681aef9ec39SRoland Dreier .eh_host_reset_handler = srp_reset_host, 1682dd5e6e38SBart Van Assche .can_queue = SRP_CMD_SQ_SIZE, 1683aef9ec39SRoland Dreier .this_id = -1, 1684dd5e6e38SBart Van Assche .cmd_per_lun = SRP_CMD_SQ_SIZE, 16856ecb0c84SRoland Dreier .use_clustering = ENABLE_CLUSTERING, 16866ecb0c84SRoland Dreier .shost_attrs = srp_host_attrs 1687aef9ec39SRoland Dreier }; 1688aef9ec39SRoland Dreier 1689aef9ec39SRoland Dreier static int srp_add_target(struct srp_host *host, struct srp_target_port *target) 1690aef9ec39SRoland Dreier { 16913236822bSFUJITA Tomonori struct srp_rport_identifiers ids; 16923236822bSFUJITA Tomonori struct srp_rport *rport; 16933236822bSFUJITA Tomonori 1694aef9ec39SRoland Dreier sprintf(target->target_name, "SRP.T10:%016llX", 1695aef9ec39SRoland Dreier (unsigned long long) be64_to_cpu(target->id_ext)); 1696aef9ec39SRoland Dreier 169705321937SGreg Kroah-Hartman if (scsi_add_host(target->scsi_host, host->srp_dev->dev->dma_device)) 1698aef9ec39SRoland Dreier return -ENODEV; 1699aef9ec39SRoland Dreier 17003236822bSFUJITA Tomonori memcpy(ids.port_id, &target->id_ext, 8); 17013236822bSFUJITA Tomonori memcpy(ids.port_id + 8, &target->ioc_guid, 8); 1702aebd5e47SFUJITA Tomonori ids.roles = SRP_RPORT_ROLE_TARGET; 17033236822bSFUJITA Tomonori rport = srp_rport_add(target->scsi_host, &ids); 17043236822bSFUJITA Tomonori if (IS_ERR(rport)) { 17053236822bSFUJITA Tomonori scsi_remove_host(target->scsi_host); 17063236822bSFUJITA Tomonori return PTR_ERR(rport); 17073236822bSFUJITA Tomonori } 17083236822bSFUJITA Tomonori 1709b3589fd4SMatthew Wilcox spin_lock(&host->target_lock); 1710aef9ec39SRoland Dreier list_add_tail(&target->list, &host->target_list); 1711b3589fd4SMatthew Wilcox spin_unlock(&host->target_lock); 1712aef9ec39SRoland Dreier 1713aef9ec39SRoland Dreier target->state = SRP_TARGET_LIVE; 1714aef9ec39SRoland Dreier 1715aef9ec39SRoland Dreier scsi_scan_target(&target->scsi_host->shost_gendev, 17161962a4a1SMatthew Wilcox 0, target->scsi_id, SCAN_WILD_CARD, 0); 1717aef9ec39SRoland Dreier 1718aef9ec39SRoland Dreier return 0; 1719aef9ec39SRoland Dreier } 1720aef9ec39SRoland Dreier 1721ee959b00STony Jones static void srp_release_dev(struct device *dev) 1722aef9ec39SRoland Dreier { 1723aef9ec39SRoland Dreier struct srp_host *host = 1724ee959b00STony Jones container_of(dev, struct srp_host, dev); 1725aef9ec39SRoland Dreier 1726aef9ec39SRoland Dreier complete(&host->released); 1727aef9ec39SRoland Dreier } 1728aef9ec39SRoland Dreier 1729aef9ec39SRoland Dreier static struct class srp_class = { 1730aef9ec39SRoland Dreier .name = "infiniband_srp", 1731ee959b00STony Jones .dev_release = srp_release_dev 1732aef9ec39SRoland Dreier }; 1733aef9ec39SRoland Dreier 1734aef9ec39SRoland Dreier /* 1735aef9ec39SRoland Dreier * Target ports are added by writing 1736aef9ec39SRoland Dreier * 1737aef9ec39SRoland Dreier * id_ext=<SRP ID ext>,ioc_guid=<SRP IOC GUID>,dgid=<dest GID>, 1738aef9ec39SRoland Dreier * pkey=<P_Key>,service_id=<service ID> 1739aef9ec39SRoland Dreier * 1740aef9ec39SRoland Dreier * to the add_target sysfs attribute. 1741aef9ec39SRoland Dreier */ 1742aef9ec39SRoland Dreier enum { 1743aef9ec39SRoland Dreier SRP_OPT_ERR = 0, 1744aef9ec39SRoland Dreier SRP_OPT_ID_EXT = 1 << 0, 1745aef9ec39SRoland Dreier SRP_OPT_IOC_GUID = 1 << 1, 1746aef9ec39SRoland Dreier SRP_OPT_DGID = 1 << 2, 1747aef9ec39SRoland Dreier SRP_OPT_PKEY = 1 << 3, 1748aef9ec39SRoland Dreier SRP_OPT_SERVICE_ID = 1 << 4, 1749aef9ec39SRoland Dreier SRP_OPT_MAX_SECT = 1 << 5, 175052fb2b50SVu Pham SRP_OPT_MAX_CMD_PER_LUN = 1 << 6, 17510c0450dbSRamachandra K SRP_OPT_IO_CLASS = 1 << 7, 175201cb9bcbSIshai Rabinovitz SRP_OPT_INITIATOR_EXT = 1 << 8, 1753aef9ec39SRoland Dreier SRP_OPT_ALL = (SRP_OPT_ID_EXT | 1754aef9ec39SRoland Dreier SRP_OPT_IOC_GUID | 1755aef9ec39SRoland Dreier SRP_OPT_DGID | 1756aef9ec39SRoland Dreier SRP_OPT_PKEY | 1757aef9ec39SRoland Dreier SRP_OPT_SERVICE_ID), 1758aef9ec39SRoland Dreier }; 1759aef9ec39SRoland Dreier 1760a447c093SSteven Whitehouse static const match_table_t srp_opt_tokens = { 1761aef9ec39SRoland Dreier { SRP_OPT_ID_EXT, "id_ext=%s" }, 1762aef9ec39SRoland Dreier { SRP_OPT_IOC_GUID, "ioc_guid=%s" }, 1763aef9ec39SRoland Dreier { SRP_OPT_DGID, "dgid=%s" }, 1764aef9ec39SRoland Dreier { SRP_OPT_PKEY, "pkey=%x" }, 1765aef9ec39SRoland Dreier { SRP_OPT_SERVICE_ID, "service_id=%s" }, 1766aef9ec39SRoland Dreier { SRP_OPT_MAX_SECT, "max_sect=%d" }, 176752fb2b50SVu Pham { SRP_OPT_MAX_CMD_PER_LUN, "max_cmd_per_lun=%d" }, 17680c0450dbSRamachandra K { SRP_OPT_IO_CLASS, "io_class=%x" }, 176901cb9bcbSIshai Rabinovitz { SRP_OPT_INITIATOR_EXT, "initiator_ext=%s" }, 1770aef9ec39SRoland Dreier { SRP_OPT_ERR, NULL } 1771aef9ec39SRoland Dreier }; 1772aef9ec39SRoland Dreier 1773aef9ec39SRoland Dreier static int srp_parse_options(const char *buf, struct srp_target_port *target) 1774aef9ec39SRoland Dreier { 1775aef9ec39SRoland Dreier char *options, *sep_opt; 1776aef9ec39SRoland Dreier char *p; 1777aef9ec39SRoland Dreier char dgid[3]; 1778aef9ec39SRoland Dreier substring_t args[MAX_OPT_ARGS]; 1779aef9ec39SRoland Dreier int opt_mask = 0; 1780aef9ec39SRoland Dreier int token; 1781aef9ec39SRoland Dreier int ret = -EINVAL; 1782aef9ec39SRoland Dreier int i; 1783aef9ec39SRoland Dreier 1784aef9ec39SRoland Dreier options = kstrdup(buf, GFP_KERNEL); 1785aef9ec39SRoland Dreier if (!options) 1786aef9ec39SRoland Dreier return -ENOMEM; 1787aef9ec39SRoland Dreier 1788aef9ec39SRoland Dreier sep_opt = options; 1789aef9ec39SRoland Dreier while ((p = strsep(&sep_opt, ",")) != NULL) { 1790aef9ec39SRoland Dreier if (!*p) 1791aef9ec39SRoland Dreier continue; 1792aef9ec39SRoland Dreier 1793aef9ec39SRoland Dreier token = match_token(p, srp_opt_tokens, args); 1794aef9ec39SRoland Dreier opt_mask |= token; 1795aef9ec39SRoland Dreier 1796aef9ec39SRoland Dreier switch (token) { 1797aef9ec39SRoland Dreier case SRP_OPT_ID_EXT: 1798aef9ec39SRoland Dreier p = match_strdup(args); 1799a20f3a6dSIshai Rabinovitz if (!p) { 1800a20f3a6dSIshai Rabinovitz ret = -ENOMEM; 1801a20f3a6dSIshai Rabinovitz goto out; 1802a20f3a6dSIshai Rabinovitz } 1803aef9ec39SRoland Dreier target->id_ext = cpu_to_be64(simple_strtoull(p, NULL, 16)); 1804aef9ec39SRoland Dreier kfree(p); 1805aef9ec39SRoland Dreier break; 1806aef9ec39SRoland Dreier 1807aef9ec39SRoland Dreier case SRP_OPT_IOC_GUID: 1808aef9ec39SRoland Dreier p = match_strdup(args); 1809a20f3a6dSIshai Rabinovitz if (!p) { 1810a20f3a6dSIshai Rabinovitz ret = -ENOMEM; 1811a20f3a6dSIshai Rabinovitz goto out; 1812a20f3a6dSIshai Rabinovitz } 1813aef9ec39SRoland Dreier target->ioc_guid = cpu_to_be64(simple_strtoull(p, NULL, 16)); 1814aef9ec39SRoland Dreier kfree(p); 1815aef9ec39SRoland Dreier break; 1816aef9ec39SRoland Dreier 1817aef9ec39SRoland Dreier case SRP_OPT_DGID: 1818aef9ec39SRoland Dreier p = match_strdup(args); 1819a20f3a6dSIshai Rabinovitz if (!p) { 1820a20f3a6dSIshai Rabinovitz ret = -ENOMEM; 1821a20f3a6dSIshai Rabinovitz goto out; 1822a20f3a6dSIshai Rabinovitz } 1823aef9ec39SRoland Dreier if (strlen(p) != 32) { 1824aef9ec39SRoland Dreier printk(KERN_WARNING PFX "bad dest GID parameter '%s'\n", p); 1825ce1823f0SRoland Dreier kfree(p); 1826aef9ec39SRoland Dreier goto out; 1827aef9ec39SRoland Dreier } 1828aef9ec39SRoland Dreier 1829aef9ec39SRoland Dreier for (i = 0; i < 16; ++i) { 1830aef9ec39SRoland Dreier strlcpy(dgid, p + i * 2, 3); 1831aef9ec39SRoland Dreier target->path.dgid.raw[i] = simple_strtoul(dgid, NULL, 16); 1832aef9ec39SRoland Dreier } 1833bf17c1c7SRoland Dreier kfree(p); 18343633b3d0SIshai Rabinovitz memcpy(target->orig_dgid, target->path.dgid.raw, 16); 1835aef9ec39SRoland Dreier break; 1836aef9ec39SRoland Dreier 1837aef9ec39SRoland Dreier case SRP_OPT_PKEY: 1838aef9ec39SRoland Dreier if (match_hex(args, &token)) { 1839aef9ec39SRoland Dreier printk(KERN_WARNING PFX "bad P_Key parameter '%s'\n", p); 1840aef9ec39SRoland Dreier goto out; 1841aef9ec39SRoland Dreier } 1842aef9ec39SRoland Dreier target->path.pkey = cpu_to_be16(token); 1843aef9ec39SRoland Dreier break; 1844aef9ec39SRoland Dreier 1845aef9ec39SRoland Dreier case SRP_OPT_SERVICE_ID: 1846aef9ec39SRoland Dreier p = match_strdup(args); 1847a20f3a6dSIshai Rabinovitz if (!p) { 1848a20f3a6dSIshai Rabinovitz ret = -ENOMEM; 1849a20f3a6dSIshai Rabinovitz goto out; 1850a20f3a6dSIshai Rabinovitz } 1851aef9ec39SRoland Dreier target->service_id = cpu_to_be64(simple_strtoull(p, NULL, 16)); 1852247e020eSSean Hefty target->path.service_id = target->service_id; 1853aef9ec39SRoland Dreier kfree(p); 1854aef9ec39SRoland Dreier break; 1855aef9ec39SRoland Dreier 1856aef9ec39SRoland Dreier case SRP_OPT_MAX_SECT: 1857aef9ec39SRoland Dreier if (match_int(args, &token)) { 1858aef9ec39SRoland Dreier printk(KERN_WARNING PFX "bad max sect parameter '%s'\n", p); 1859aef9ec39SRoland Dreier goto out; 1860aef9ec39SRoland Dreier } 1861aef9ec39SRoland Dreier target->scsi_host->max_sectors = token; 1862aef9ec39SRoland Dreier break; 1863aef9ec39SRoland Dreier 186452fb2b50SVu Pham case SRP_OPT_MAX_CMD_PER_LUN: 186552fb2b50SVu Pham if (match_int(args, &token)) { 186652fb2b50SVu Pham printk(KERN_WARNING PFX "bad max cmd_per_lun parameter '%s'\n", p); 186752fb2b50SVu Pham goto out; 186852fb2b50SVu Pham } 1869dd5e6e38SBart Van Assche target->scsi_host->cmd_per_lun = min(token, SRP_CMD_SQ_SIZE); 187052fb2b50SVu Pham break; 187152fb2b50SVu Pham 18720c0450dbSRamachandra K case SRP_OPT_IO_CLASS: 18730c0450dbSRamachandra K if (match_hex(args, &token)) { 18740c0450dbSRamachandra K printk(KERN_WARNING PFX "bad IO class parameter '%s' \n", p); 18750c0450dbSRamachandra K goto out; 18760c0450dbSRamachandra K } 18770c0450dbSRamachandra K if (token != SRP_REV10_IB_IO_CLASS && 18780c0450dbSRamachandra K token != SRP_REV16A_IB_IO_CLASS) { 18790c0450dbSRamachandra K printk(KERN_WARNING PFX "unknown IO class parameter value" 18800c0450dbSRamachandra K " %x specified (use %x or %x).\n", 18810c0450dbSRamachandra K token, SRP_REV10_IB_IO_CLASS, SRP_REV16A_IB_IO_CLASS); 18820c0450dbSRamachandra K goto out; 18830c0450dbSRamachandra K } 18840c0450dbSRamachandra K target->io_class = token; 18850c0450dbSRamachandra K break; 18860c0450dbSRamachandra K 188701cb9bcbSIshai Rabinovitz case SRP_OPT_INITIATOR_EXT: 188801cb9bcbSIshai Rabinovitz p = match_strdup(args); 1889a20f3a6dSIshai Rabinovitz if (!p) { 1890a20f3a6dSIshai Rabinovitz ret = -ENOMEM; 1891a20f3a6dSIshai Rabinovitz goto out; 1892a20f3a6dSIshai Rabinovitz } 189301cb9bcbSIshai Rabinovitz target->initiator_ext = cpu_to_be64(simple_strtoull(p, NULL, 16)); 189401cb9bcbSIshai Rabinovitz kfree(p); 189501cb9bcbSIshai Rabinovitz break; 189601cb9bcbSIshai Rabinovitz 1897aef9ec39SRoland Dreier default: 1898aef9ec39SRoland Dreier printk(KERN_WARNING PFX "unknown parameter or missing value " 1899aef9ec39SRoland Dreier "'%s' in target creation request\n", p); 1900aef9ec39SRoland Dreier goto out; 1901aef9ec39SRoland Dreier } 1902aef9ec39SRoland Dreier } 1903aef9ec39SRoland Dreier 1904aef9ec39SRoland Dreier if ((opt_mask & SRP_OPT_ALL) == SRP_OPT_ALL) 1905aef9ec39SRoland Dreier ret = 0; 1906aef9ec39SRoland Dreier else 1907aef9ec39SRoland Dreier for (i = 0; i < ARRAY_SIZE(srp_opt_tokens); ++i) 1908aef9ec39SRoland Dreier if ((srp_opt_tokens[i].token & SRP_OPT_ALL) && 1909aef9ec39SRoland Dreier !(srp_opt_tokens[i].token & opt_mask)) 1910aef9ec39SRoland Dreier printk(KERN_WARNING PFX "target creation request is " 1911aef9ec39SRoland Dreier "missing parameter '%s'\n", 1912aef9ec39SRoland Dreier srp_opt_tokens[i].pattern); 1913aef9ec39SRoland Dreier 1914aef9ec39SRoland Dreier out: 1915aef9ec39SRoland Dreier kfree(options); 1916aef9ec39SRoland Dreier return ret; 1917aef9ec39SRoland Dreier } 1918aef9ec39SRoland Dreier 1919ee959b00STony Jones static ssize_t srp_create_target(struct device *dev, 1920ee959b00STony Jones struct device_attribute *attr, 1921aef9ec39SRoland Dreier const char *buf, size_t count) 1922aef9ec39SRoland Dreier { 1923aef9ec39SRoland Dreier struct srp_host *host = 1924ee959b00STony Jones container_of(dev, struct srp_host, dev); 1925aef9ec39SRoland Dreier struct Scsi_Host *target_host; 1926aef9ec39SRoland Dreier struct srp_target_port *target; 1927aef9ec39SRoland Dreier int ret; 1928aef9ec39SRoland Dreier int i; 1929aef9ec39SRoland Dreier 1930aef9ec39SRoland Dreier target_host = scsi_host_alloc(&srp_template, 1931aef9ec39SRoland Dreier sizeof (struct srp_target_port)); 1932aef9ec39SRoland Dreier if (!target_host) 1933aef9ec39SRoland Dreier return -ENOMEM; 1934aef9ec39SRoland Dreier 19353236822bSFUJITA Tomonori target_host->transportt = ib_srp_transport_template; 19365f068992SRoland Dreier target_host->max_lun = SRP_MAX_LUN; 19373c8edf0eSArne Redlich target_host->max_cmd_len = sizeof ((struct srp_cmd *) (void *) 0L)->cdb; 19385f068992SRoland Dreier 1939aef9ec39SRoland Dreier target = host_to_target(target_host); 1940aef9ec39SRoland Dreier 19410c0450dbSRamachandra K target->io_class = SRP_REV16A_IB_IO_CLASS; 1942aef9ec39SRoland Dreier target->scsi_host = target_host; 1943aef9ec39SRoland Dreier target->srp_host = host; 19449af76271SDavid Dillow target->lkey = host->srp_dev->mr->lkey; 19459af76271SDavid Dillow target->rkey = host->srp_dev->mr->rkey; 1946aef9ec39SRoland Dreier 1947e9684678SBart Van Assche spin_lock_init(&target->lock); 1948dcb4cb85SBart Van Assche INIT_LIST_HEAD(&target->free_tx); 1949d945e1dfSRoland Dreier INIT_LIST_HEAD(&target->free_reqs); 1950dd5e6e38SBart Van Assche for (i = 0; i < SRP_CMD_SQ_SIZE; ++i) { 1951d945e1dfSRoland Dreier target->req_ring[i].index = i; 1952d945e1dfSRoland Dreier list_add_tail(&target->req_ring[i].list, &target->free_reqs); 1953d945e1dfSRoland Dreier } 1954aef9ec39SRoland Dreier 1955aef9ec39SRoland Dreier ret = srp_parse_options(buf, target); 1956aef9ec39SRoland Dreier if (ret) 1957aef9ec39SRoland Dreier goto err; 1958aef9ec39SRoland Dreier 1959969a60f9SRoland Dreier ib_query_gid(host->srp_dev->dev, host->port, 0, &target->path.sgid); 1960aef9ec39SRoland Dreier 19617aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, target->scsi_host, PFX 19627aa54bd7SDavid Dillow "new target: id_ext %016llx ioc_guid %016llx pkey %04x " 19635b095d98SHarvey Harrison "service_id %016llx dgid %pI6\n", 1964aef9ec39SRoland Dreier (unsigned long long) be64_to_cpu(target->id_ext), 1965aef9ec39SRoland Dreier (unsigned long long) be64_to_cpu(target->ioc_guid), 1966aef9ec39SRoland Dreier be16_to_cpu(target->path.pkey), 1967aef9ec39SRoland Dreier (unsigned long long) be64_to_cpu(target->service_id), 19688867cd7cSHarvey Harrison target->path.dgid.raw); 1969aef9ec39SRoland Dreier 1970aef9ec39SRoland Dreier ret = srp_create_target_ib(target); 1971aef9ec39SRoland Dreier if (ret) 1972aef9ec39SRoland Dreier goto err; 1973aef9ec39SRoland Dreier 19749fe4bcf4SDavid Dillow ret = srp_new_cm_id(target); 19759fe4bcf4SDavid Dillow if (ret) 1976aef9ec39SRoland Dreier goto err_free; 1977aef9ec39SRoland Dreier 19781033ff67SIshai Rabinovitz target->qp_in_error = 0; 1979aef9ec39SRoland Dreier ret = srp_connect_target(target); 1980aef9ec39SRoland Dreier if (ret) { 19817aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 19827aa54bd7SDavid Dillow PFX "Connection failed\n"); 1983aef9ec39SRoland Dreier goto err_cm_id; 1984aef9ec39SRoland Dreier } 1985aef9ec39SRoland Dreier 1986aef9ec39SRoland Dreier ret = srp_add_target(host, target); 1987aef9ec39SRoland Dreier if (ret) 1988aef9ec39SRoland Dreier goto err_disconnect; 1989aef9ec39SRoland Dreier 1990aef9ec39SRoland Dreier return count; 1991aef9ec39SRoland Dreier 1992aef9ec39SRoland Dreier err_disconnect: 1993aef9ec39SRoland Dreier srp_disconnect_target(target); 1994aef9ec39SRoland Dreier 1995aef9ec39SRoland Dreier err_cm_id: 1996aef9ec39SRoland Dreier ib_destroy_cm_id(target->cm_id); 1997aef9ec39SRoland Dreier 1998aef9ec39SRoland Dreier err_free: 1999aef9ec39SRoland Dreier srp_free_target_ib(target); 2000aef9ec39SRoland Dreier 2001aef9ec39SRoland Dreier err: 2002aef9ec39SRoland Dreier scsi_host_put(target_host); 2003aef9ec39SRoland Dreier 2004aef9ec39SRoland Dreier return ret; 2005aef9ec39SRoland Dreier } 2006aef9ec39SRoland Dreier 2007ee959b00STony Jones static DEVICE_ATTR(add_target, S_IWUSR, NULL, srp_create_target); 2008aef9ec39SRoland Dreier 2009ee959b00STony Jones static ssize_t show_ibdev(struct device *dev, struct device_attribute *attr, 2010ee959b00STony Jones char *buf) 2011aef9ec39SRoland Dreier { 2012ee959b00STony Jones struct srp_host *host = container_of(dev, struct srp_host, dev); 2013aef9ec39SRoland Dreier 201405321937SGreg Kroah-Hartman return sprintf(buf, "%s\n", host->srp_dev->dev->name); 2015aef9ec39SRoland Dreier } 2016aef9ec39SRoland Dreier 2017ee959b00STony Jones static DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL); 2018aef9ec39SRoland Dreier 2019ee959b00STony Jones static ssize_t show_port(struct device *dev, struct device_attribute *attr, 2020ee959b00STony Jones char *buf) 2021aef9ec39SRoland Dreier { 2022ee959b00STony Jones struct srp_host *host = container_of(dev, struct srp_host, dev); 2023aef9ec39SRoland Dreier 2024aef9ec39SRoland Dreier return sprintf(buf, "%d\n", host->port); 2025aef9ec39SRoland Dreier } 2026aef9ec39SRoland Dreier 2027ee959b00STony Jones static DEVICE_ATTR(port, S_IRUGO, show_port, NULL); 2028aef9ec39SRoland Dreier 2029f5358a17SRoland Dreier static struct srp_host *srp_add_port(struct srp_device *device, u8 port) 2030aef9ec39SRoland Dreier { 2031aef9ec39SRoland Dreier struct srp_host *host; 2032aef9ec39SRoland Dreier 2033aef9ec39SRoland Dreier host = kzalloc(sizeof *host, GFP_KERNEL); 2034aef9ec39SRoland Dreier if (!host) 2035aef9ec39SRoland Dreier return NULL; 2036aef9ec39SRoland Dreier 2037aef9ec39SRoland Dreier INIT_LIST_HEAD(&host->target_list); 2038b3589fd4SMatthew Wilcox spin_lock_init(&host->target_lock); 2039aef9ec39SRoland Dreier init_completion(&host->released); 204005321937SGreg Kroah-Hartman host->srp_dev = device; 2041aef9ec39SRoland Dreier host->port = port; 2042aef9ec39SRoland Dreier 2043ee959b00STony Jones host->dev.class = &srp_class; 2044ee959b00STony Jones host->dev.parent = device->dev->dma_device; 2045d927e38cSKay Sievers dev_set_name(&host->dev, "srp-%s-%d", device->dev->name, port); 2046aef9ec39SRoland Dreier 2047ee959b00STony Jones if (device_register(&host->dev)) 2048f5358a17SRoland Dreier goto free_host; 2049ee959b00STony Jones if (device_create_file(&host->dev, &dev_attr_add_target)) 2050aef9ec39SRoland Dreier goto err_class; 2051ee959b00STony Jones if (device_create_file(&host->dev, &dev_attr_ibdev)) 2052aef9ec39SRoland Dreier goto err_class; 2053ee959b00STony Jones if (device_create_file(&host->dev, &dev_attr_port)) 2054aef9ec39SRoland Dreier goto err_class; 2055aef9ec39SRoland Dreier 2056aef9ec39SRoland Dreier return host; 2057aef9ec39SRoland Dreier 2058aef9ec39SRoland Dreier err_class: 2059ee959b00STony Jones device_unregister(&host->dev); 2060aef9ec39SRoland Dreier 2061f5358a17SRoland Dreier free_host: 2062aef9ec39SRoland Dreier kfree(host); 2063aef9ec39SRoland Dreier 2064aef9ec39SRoland Dreier return NULL; 2065aef9ec39SRoland Dreier } 2066aef9ec39SRoland Dreier 2067aef9ec39SRoland Dreier static void srp_add_one(struct ib_device *device) 2068aef9ec39SRoland Dreier { 2069f5358a17SRoland Dreier struct srp_device *srp_dev; 2070f5358a17SRoland Dreier struct ib_device_attr *dev_attr; 2071f5358a17SRoland Dreier struct ib_fmr_pool_param fmr_param; 2072aef9ec39SRoland Dreier struct srp_host *host; 2073aef9ec39SRoland Dreier int s, e, p; 2074aef9ec39SRoland Dreier 2075f5358a17SRoland Dreier dev_attr = kmalloc(sizeof *dev_attr, GFP_KERNEL); 2076f5358a17SRoland Dreier if (!dev_attr) 2077cf311cd4SSean Hefty return; 2078aef9ec39SRoland Dreier 2079f5358a17SRoland Dreier if (ib_query_device(device, dev_attr)) { 2080f5358a17SRoland Dreier printk(KERN_WARNING PFX "Query device failed for %s\n", 2081f5358a17SRoland Dreier device->name); 2082f5358a17SRoland Dreier goto free_attr; 2083f5358a17SRoland Dreier } 2084f5358a17SRoland Dreier 2085f5358a17SRoland Dreier srp_dev = kmalloc(sizeof *srp_dev, GFP_KERNEL); 2086f5358a17SRoland Dreier if (!srp_dev) 2087f5358a17SRoland Dreier goto free_attr; 2088f5358a17SRoland Dreier 2089f5358a17SRoland Dreier /* 2090f5358a17SRoland Dreier * Use the smallest page size supported by the HCA, down to a 2091f5358a17SRoland Dreier * minimum of 512 bytes (which is the smallest sector that a 2092f5358a17SRoland Dreier * SCSI command will ever carry). 2093f5358a17SRoland Dreier */ 2094f5358a17SRoland Dreier srp_dev->fmr_page_shift = max(9, ffs(dev_attr->page_size_cap) - 1); 2095f5358a17SRoland Dreier srp_dev->fmr_page_size = 1 << srp_dev->fmr_page_shift; 2096bf628dc2SRoland Dreier srp_dev->fmr_page_mask = ~((u64) srp_dev->fmr_page_size - 1); 2097f5358a17SRoland Dreier 2098f5358a17SRoland Dreier INIT_LIST_HEAD(&srp_dev->dev_list); 2099f5358a17SRoland Dreier 2100f5358a17SRoland Dreier srp_dev->dev = device; 2101f5358a17SRoland Dreier srp_dev->pd = ib_alloc_pd(device); 2102f5358a17SRoland Dreier if (IS_ERR(srp_dev->pd)) 2103f5358a17SRoland Dreier goto free_dev; 2104f5358a17SRoland Dreier 2105f5358a17SRoland Dreier srp_dev->mr = ib_get_dma_mr(srp_dev->pd, 2106f5358a17SRoland Dreier IB_ACCESS_LOCAL_WRITE | 2107f5358a17SRoland Dreier IB_ACCESS_REMOTE_READ | 2108f5358a17SRoland Dreier IB_ACCESS_REMOTE_WRITE); 2109f5358a17SRoland Dreier if (IS_ERR(srp_dev->mr)) 2110f5358a17SRoland Dreier goto err_pd; 2111f5358a17SRoland Dreier 2112f5358a17SRoland Dreier memset(&fmr_param, 0, sizeof fmr_param); 2113f5358a17SRoland Dreier fmr_param.pool_size = SRP_FMR_POOL_SIZE; 2114f5358a17SRoland Dreier fmr_param.dirty_watermark = SRP_FMR_DIRTY_SIZE; 2115f5358a17SRoland Dreier fmr_param.cache = 1; 2116f5358a17SRoland Dreier fmr_param.max_pages_per_fmr = SRP_FMR_SIZE; 2117f5358a17SRoland Dreier fmr_param.page_shift = srp_dev->fmr_page_shift; 2118f5358a17SRoland Dreier fmr_param.access = (IB_ACCESS_LOCAL_WRITE | 2119f5358a17SRoland Dreier IB_ACCESS_REMOTE_WRITE | 2120f5358a17SRoland Dreier IB_ACCESS_REMOTE_READ); 2121f5358a17SRoland Dreier 2122f5358a17SRoland Dreier srp_dev->fmr_pool = ib_create_fmr_pool(srp_dev->pd, &fmr_param); 2123f5358a17SRoland Dreier if (IS_ERR(srp_dev->fmr_pool)) 2124f5358a17SRoland Dreier srp_dev->fmr_pool = NULL; 2125aef9ec39SRoland Dreier 212607ebafbaSTom Tucker if (device->node_type == RDMA_NODE_IB_SWITCH) { 2127aef9ec39SRoland Dreier s = 0; 2128aef9ec39SRoland Dreier e = 0; 2129aef9ec39SRoland Dreier } else { 2130aef9ec39SRoland Dreier s = 1; 2131aef9ec39SRoland Dreier e = device->phys_port_cnt; 2132aef9ec39SRoland Dreier } 2133aef9ec39SRoland Dreier 2134aef9ec39SRoland Dreier for (p = s; p <= e; ++p) { 2135f5358a17SRoland Dreier host = srp_add_port(srp_dev, p); 2136aef9ec39SRoland Dreier if (host) 2137f5358a17SRoland Dreier list_add_tail(&host->list, &srp_dev->dev_list); 2138aef9ec39SRoland Dreier } 2139aef9ec39SRoland Dreier 2140f5358a17SRoland Dreier ib_set_client_data(device, &srp_client, srp_dev); 2141f5358a17SRoland Dreier 2142f5358a17SRoland Dreier goto free_attr; 2143f5358a17SRoland Dreier 2144f5358a17SRoland Dreier err_pd: 2145f5358a17SRoland Dreier ib_dealloc_pd(srp_dev->pd); 2146f5358a17SRoland Dreier 2147f5358a17SRoland Dreier free_dev: 2148f5358a17SRoland Dreier kfree(srp_dev); 2149f5358a17SRoland Dreier 2150f5358a17SRoland Dreier free_attr: 2151f5358a17SRoland Dreier kfree(dev_attr); 2152aef9ec39SRoland Dreier } 2153aef9ec39SRoland Dreier 2154aef9ec39SRoland Dreier static void srp_remove_one(struct ib_device *device) 2155aef9ec39SRoland Dreier { 2156f5358a17SRoland Dreier struct srp_device *srp_dev; 2157aef9ec39SRoland Dreier struct srp_host *host, *tmp_host; 2158aef9ec39SRoland Dreier LIST_HEAD(target_list); 2159aef9ec39SRoland Dreier struct srp_target_port *target, *tmp_target; 2160aef9ec39SRoland Dreier 2161f5358a17SRoland Dreier srp_dev = ib_get_client_data(device, &srp_client); 2162aef9ec39SRoland Dreier 2163f5358a17SRoland Dreier list_for_each_entry_safe(host, tmp_host, &srp_dev->dev_list, list) { 2164ee959b00STony Jones device_unregister(&host->dev); 2165aef9ec39SRoland Dreier /* 2166aef9ec39SRoland Dreier * Wait for the sysfs entry to go away, so that no new 2167aef9ec39SRoland Dreier * target ports can be created. 2168aef9ec39SRoland Dreier */ 2169aef9ec39SRoland Dreier wait_for_completion(&host->released); 2170aef9ec39SRoland Dreier 2171aef9ec39SRoland Dreier /* 2172aef9ec39SRoland Dreier * Mark all target ports as removed, so we stop queueing 2173aef9ec39SRoland Dreier * commands and don't try to reconnect. 2174aef9ec39SRoland Dreier */ 2175b3589fd4SMatthew Wilcox spin_lock(&host->target_lock); 2176549c5fc2SMatthew Wilcox list_for_each_entry(target, &host->target_list, list) { 2177e9684678SBart Van Assche spin_lock_irq(&target->lock); 2178aef9ec39SRoland Dreier target->state = SRP_TARGET_REMOVED; 2179e9684678SBart Van Assche spin_unlock_irq(&target->lock); 2180aef9ec39SRoland Dreier } 2181b3589fd4SMatthew Wilcox spin_unlock(&host->target_lock); 2182aef9ec39SRoland Dreier 2183aef9ec39SRoland Dreier /* 2184aef9ec39SRoland Dreier * Wait for any reconnection tasks that may have 2185aef9ec39SRoland Dreier * started before we marked our target ports as 2186aef9ec39SRoland Dreier * removed, and any target port removal tasks. 2187aef9ec39SRoland Dreier */ 2188f0626710STejun Heo flush_workqueue(ib_wq); 2189aef9ec39SRoland Dreier 2190aef9ec39SRoland Dreier list_for_each_entry_safe(target, tmp_target, 2191aef9ec39SRoland Dreier &host->target_list, list) { 2192b0e47c8bSDavid Dillow srp_remove_host(target->scsi_host); 2193ad696989SDave Dillow scsi_remove_host(target->scsi_host); 2194aef9ec39SRoland Dreier srp_disconnect_target(target); 2195aef9ec39SRoland Dreier ib_destroy_cm_id(target->cm_id); 2196aef9ec39SRoland Dreier srp_free_target_ib(target); 2197aef9ec39SRoland Dreier scsi_host_put(target->scsi_host); 2198aef9ec39SRoland Dreier } 2199aef9ec39SRoland Dreier 2200aef9ec39SRoland Dreier kfree(host); 2201aef9ec39SRoland Dreier } 2202aef9ec39SRoland Dreier 2203f5358a17SRoland Dreier if (srp_dev->fmr_pool) 2204f5358a17SRoland Dreier ib_destroy_fmr_pool(srp_dev->fmr_pool); 2205f5358a17SRoland Dreier ib_dereg_mr(srp_dev->mr); 2206f5358a17SRoland Dreier ib_dealloc_pd(srp_dev->pd); 2207f5358a17SRoland Dreier 2208f5358a17SRoland Dreier kfree(srp_dev); 2209aef9ec39SRoland Dreier } 2210aef9ec39SRoland Dreier 22113236822bSFUJITA Tomonori static struct srp_function_template ib_srp_transport_functions = { 22123236822bSFUJITA Tomonori }; 22133236822bSFUJITA Tomonori 2214aef9ec39SRoland Dreier static int __init srp_init_module(void) 2215aef9ec39SRoland Dreier { 2216aef9ec39SRoland Dreier int ret; 2217aef9ec39SRoland Dreier 2218dcb4cb85SBart Van Assche BUILD_BUG_ON(FIELD_SIZEOF(struct ib_wc, wr_id) < sizeof(void *)); 2219dd5e6e38SBart Van Assche 22201e89a194SDavid Dillow if (srp_sg_tablesize > 255) { 22211e89a194SDavid Dillow printk(KERN_WARNING PFX "Clamping srp_sg_tablesize to 255\n"); 22221e89a194SDavid Dillow srp_sg_tablesize = 255; 22231e89a194SDavid Dillow } 22241e89a194SDavid Dillow 22253236822bSFUJITA Tomonori ib_srp_transport_template = 22263236822bSFUJITA Tomonori srp_attach_transport(&ib_srp_transport_functions); 22273236822bSFUJITA Tomonori if (!ib_srp_transport_template) 22283236822bSFUJITA Tomonori return -ENOMEM; 22293236822bSFUJITA Tomonori 223074b0a15bSVu Pham srp_template.sg_tablesize = srp_sg_tablesize; 223174b0a15bSVu Pham srp_max_iu_len = (sizeof (struct srp_cmd) + 223274b0a15bSVu Pham sizeof (struct srp_indirect_buf) + 223374b0a15bSVu Pham srp_sg_tablesize * 16); 223474b0a15bSVu Pham 2235aef9ec39SRoland Dreier ret = class_register(&srp_class); 2236aef9ec39SRoland Dreier if (ret) { 2237aef9ec39SRoland Dreier printk(KERN_ERR PFX "couldn't register class infiniband_srp\n"); 22383236822bSFUJITA Tomonori srp_release_transport(ib_srp_transport_template); 2239aef9ec39SRoland Dreier return ret; 2240aef9ec39SRoland Dreier } 2241aef9ec39SRoland Dreier 2242c1a0b23bSMichael S. Tsirkin ib_sa_register_client(&srp_sa_client); 2243c1a0b23bSMichael S. Tsirkin 2244aef9ec39SRoland Dreier ret = ib_register_client(&srp_client); 2245aef9ec39SRoland Dreier if (ret) { 2246aef9ec39SRoland Dreier printk(KERN_ERR PFX "couldn't register IB client\n"); 22473236822bSFUJITA Tomonori srp_release_transport(ib_srp_transport_template); 2248c1a0b23bSMichael S. Tsirkin ib_sa_unregister_client(&srp_sa_client); 2249aef9ec39SRoland Dreier class_unregister(&srp_class); 2250aef9ec39SRoland Dreier return ret; 2251aef9ec39SRoland Dreier } 2252aef9ec39SRoland Dreier 2253aef9ec39SRoland Dreier return 0; 2254aef9ec39SRoland Dreier } 2255aef9ec39SRoland Dreier 2256aef9ec39SRoland Dreier static void __exit srp_cleanup_module(void) 2257aef9ec39SRoland Dreier { 2258aef9ec39SRoland Dreier ib_unregister_client(&srp_client); 2259c1a0b23bSMichael S. Tsirkin ib_sa_unregister_client(&srp_sa_client); 2260aef9ec39SRoland Dreier class_unregister(&srp_class); 22613236822bSFUJITA Tomonori srp_release_transport(ib_srp_transport_template); 2262aef9ec39SRoland Dreier } 2263aef9ec39SRoland Dreier 2264aef9ec39SRoland Dreier module_init(srp_init_module); 2265aef9ec39SRoland Dreier module_exit(srp_cleanup_module); 2266