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 75559ce8f1SIshai Rabinovitz static int mellanox_workarounds = 1; 76559ce8f1SIshai Rabinovitz 77559ce8f1SIshai Rabinovitz module_param(mellanox_workarounds, int, 0444); 78559ce8f1SIshai Rabinovitz MODULE_PARM_DESC(mellanox_workarounds, 79559ce8f1SIshai Rabinovitz "Enable workarounds for Mellanox SRP target bugs if != 0"); 80559ce8f1SIshai Rabinovitz 81aef9ec39SRoland Dreier static void srp_add_one(struct ib_device *device); 82aef9ec39SRoland Dreier static void srp_remove_one(struct ib_device *device); 83aef9ec39SRoland Dreier static void srp_completion(struct ib_cq *cq, void *target_ptr); 84aef9ec39SRoland Dreier static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event); 85aef9ec39SRoland Dreier 863236822bSFUJITA Tomonori static struct scsi_transport_template *ib_srp_transport_template; 873236822bSFUJITA Tomonori 88aef9ec39SRoland Dreier static struct ib_client srp_client = { 89aef9ec39SRoland Dreier .name = "srp", 90aef9ec39SRoland Dreier .add = srp_add_one, 91aef9ec39SRoland Dreier .remove = srp_remove_one 92aef9ec39SRoland Dreier }; 93aef9ec39SRoland Dreier 94c1a0b23bSMichael S. Tsirkin static struct ib_sa_client srp_sa_client; 95c1a0b23bSMichael S. Tsirkin 96aef9ec39SRoland Dreier static inline struct srp_target_port *host_to_target(struct Scsi_Host *host) 97aef9ec39SRoland Dreier { 98aef9ec39SRoland Dreier return (struct srp_target_port *) host->hostdata; 99aef9ec39SRoland Dreier } 100aef9ec39SRoland Dreier 101aef9ec39SRoland Dreier static const char *srp_target_info(struct Scsi_Host *host) 102aef9ec39SRoland Dreier { 103aef9ec39SRoland Dreier return host_to_target(host)->target_name; 104aef9ec39SRoland Dreier } 105aef9ec39SRoland Dreier 1065d7cbfd6SRoland Dreier static int srp_target_is_topspin(struct srp_target_port *target) 1075d7cbfd6SRoland Dreier { 1085d7cbfd6SRoland Dreier static const u8 topspin_oui[3] = { 0x00, 0x05, 0xad }; 1093d1ff48dSRaghava Kondapalli static const u8 cisco_oui[3] = { 0x00, 0x1b, 0x0d }; 1105d7cbfd6SRoland Dreier 1115d7cbfd6SRoland Dreier return topspin_workarounds && 1123d1ff48dSRaghava Kondapalli (!memcmp(&target->ioc_guid, topspin_oui, sizeof topspin_oui) || 1133d1ff48dSRaghava Kondapalli !memcmp(&target->ioc_guid, cisco_oui, sizeof cisco_oui)); 1145d7cbfd6SRoland Dreier } 1155d7cbfd6SRoland Dreier 1165d7cbfd6SRoland Dreier static int srp_target_is_mellanox(struct srp_target_port *target) 1175d7cbfd6SRoland Dreier { 1185d7cbfd6SRoland Dreier static const u8 mellanox_oui[3] = { 0x00, 0x02, 0xc9 }; 1195d7cbfd6SRoland Dreier 1205d7cbfd6SRoland Dreier return mellanox_workarounds && 1215d7cbfd6SRoland Dreier !memcmp(&target->ioc_guid, mellanox_oui, sizeof mellanox_oui); 1225d7cbfd6SRoland Dreier } 1235d7cbfd6SRoland Dreier 124aef9ec39SRoland Dreier static struct srp_iu *srp_alloc_iu(struct srp_host *host, size_t size, 125aef9ec39SRoland Dreier gfp_t gfp_mask, 126aef9ec39SRoland Dreier enum dma_data_direction direction) 127aef9ec39SRoland Dreier { 128aef9ec39SRoland Dreier struct srp_iu *iu; 129aef9ec39SRoland Dreier 130aef9ec39SRoland Dreier iu = kmalloc(sizeof *iu, gfp_mask); 131aef9ec39SRoland Dreier if (!iu) 132aef9ec39SRoland Dreier goto out; 133aef9ec39SRoland Dreier 134aef9ec39SRoland Dreier iu->buf = kzalloc(size, gfp_mask); 135aef9ec39SRoland Dreier if (!iu->buf) 136aef9ec39SRoland Dreier goto out_free_iu; 137aef9ec39SRoland Dreier 13805321937SGreg Kroah-Hartman iu->dma = ib_dma_map_single(host->srp_dev->dev, iu->buf, size, 13905321937SGreg Kroah-Hartman direction); 14005321937SGreg Kroah-Hartman if (ib_dma_mapping_error(host->srp_dev->dev, iu->dma)) 141aef9ec39SRoland Dreier goto out_free_buf; 142aef9ec39SRoland Dreier 143aef9ec39SRoland Dreier iu->size = size; 144aef9ec39SRoland Dreier iu->direction = direction; 145aef9ec39SRoland Dreier 146aef9ec39SRoland Dreier return iu; 147aef9ec39SRoland Dreier 148aef9ec39SRoland Dreier out_free_buf: 149aef9ec39SRoland Dreier kfree(iu->buf); 150aef9ec39SRoland Dreier out_free_iu: 151aef9ec39SRoland Dreier kfree(iu); 152aef9ec39SRoland Dreier out: 153aef9ec39SRoland Dreier return NULL; 154aef9ec39SRoland Dreier } 155aef9ec39SRoland Dreier 156aef9ec39SRoland Dreier static void srp_free_iu(struct srp_host *host, struct srp_iu *iu) 157aef9ec39SRoland Dreier { 158aef9ec39SRoland Dreier if (!iu) 159aef9ec39SRoland Dreier return; 160aef9ec39SRoland Dreier 16105321937SGreg Kroah-Hartman ib_dma_unmap_single(host->srp_dev->dev, iu->dma, iu->size, 16205321937SGreg Kroah-Hartman iu->direction); 163aef9ec39SRoland Dreier kfree(iu->buf); 164aef9ec39SRoland Dreier kfree(iu); 165aef9ec39SRoland Dreier } 166aef9ec39SRoland Dreier 167aef9ec39SRoland Dreier static void srp_qp_event(struct ib_event *event, void *context) 168aef9ec39SRoland Dreier { 169aef9ec39SRoland Dreier printk(KERN_ERR PFX "QP event %d\n", event->event); 170aef9ec39SRoland Dreier } 171aef9ec39SRoland Dreier 172aef9ec39SRoland Dreier static int srp_init_qp(struct srp_target_port *target, 173aef9ec39SRoland Dreier struct ib_qp *qp) 174aef9ec39SRoland Dreier { 175aef9ec39SRoland Dreier struct ib_qp_attr *attr; 176aef9ec39SRoland Dreier int ret; 177aef9ec39SRoland Dreier 178aef9ec39SRoland Dreier attr = kmalloc(sizeof *attr, GFP_KERNEL); 179aef9ec39SRoland Dreier if (!attr) 180aef9ec39SRoland Dreier return -ENOMEM; 181aef9ec39SRoland Dreier 182969a60f9SRoland Dreier ret = ib_find_pkey(target->srp_host->srp_dev->dev, 183aef9ec39SRoland Dreier target->srp_host->port, 184aef9ec39SRoland Dreier be16_to_cpu(target->path.pkey), 185aef9ec39SRoland Dreier &attr->pkey_index); 186aef9ec39SRoland Dreier if (ret) 187aef9ec39SRoland Dreier goto out; 188aef9ec39SRoland Dreier 189aef9ec39SRoland Dreier attr->qp_state = IB_QPS_INIT; 190aef9ec39SRoland Dreier attr->qp_access_flags = (IB_ACCESS_REMOTE_READ | 191aef9ec39SRoland Dreier IB_ACCESS_REMOTE_WRITE); 192aef9ec39SRoland Dreier attr->port_num = target->srp_host->port; 193aef9ec39SRoland Dreier 194aef9ec39SRoland Dreier ret = ib_modify_qp(qp, attr, 195aef9ec39SRoland Dreier IB_QP_STATE | 196aef9ec39SRoland Dreier IB_QP_PKEY_INDEX | 197aef9ec39SRoland Dreier IB_QP_ACCESS_FLAGS | 198aef9ec39SRoland Dreier IB_QP_PORT); 199aef9ec39SRoland Dreier 200aef9ec39SRoland Dreier out: 201aef9ec39SRoland Dreier kfree(attr); 202aef9ec39SRoland Dreier return ret; 203aef9ec39SRoland Dreier } 204aef9ec39SRoland Dreier 2059fe4bcf4SDavid Dillow static int srp_new_cm_id(struct srp_target_port *target) 2069fe4bcf4SDavid Dillow { 2079fe4bcf4SDavid Dillow struct ib_cm_id *new_cm_id; 2089fe4bcf4SDavid Dillow 20905321937SGreg Kroah-Hartman new_cm_id = ib_create_cm_id(target->srp_host->srp_dev->dev, 2109fe4bcf4SDavid Dillow srp_cm_handler, target); 2119fe4bcf4SDavid Dillow if (IS_ERR(new_cm_id)) 2129fe4bcf4SDavid Dillow return PTR_ERR(new_cm_id); 2139fe4bcf4SDavid Dillow 2149fe4bcf4SDavid Dillow if (target->cm_id) 2159fe4bcf4SDavid Dillow ib_destroy_cm_id(target->cm_id); 2169fe4bcf4SDavid Dillow target->cm_id = new_cm_id; 2179fe4bcf4SDavid Dillow 2189fe4bcf4SDavid Dillow return 0; 2199fe4bcf4SDavid Dillow } 2209fe4bcf4SDavid Dillow 221aef9ec39SRoland Dreier static int srp_create_target_ib(struct srp_target_port *target) 222aef9ec39SRoland Dreier { 223aef9ec39SRoland Dreier struct ib_qp_init_attr *init_attr; 224aef9ec39SRoland Dreier int ret; 225aef9ec39SRoland Dreier 226aef9ec39SRoland Dreier init_attr = kzalloc(sizeof *init_attr, GFP_KERNEL); 227aef9ec39SRoland Dreier if (!init_attr) 228aef9ec39SRoland Dreier return -ENOMEM; 229aef9ec39SRoland Dreier 23005321937SGreg Kroah-Hartman target->cq = ib_create_cq(target->srp_host->srp_dev->dev, 23105321937SGreg Kroah-Hartman srp_completion, NULL, target, SRP_CQ_SIZE, 0); 232aef9ec39SRoland Dreier if (IS_ERR(target->cq)) { 233aef9ec39SRoland Dreier ret = PTR_ERR(target->cq); 234aef9ec39SRoland Dreier goto out; 235aef9ec39SRoland Dreier } 236aef9ec39SRoland Dreier 237aef9ec39SRoland Dreier ib_req_notify_cq(target->cq, IB_CQ_NEXT_COMP); 238aef9ec39SRoland Dreier 239aef9ec39SRoland Dreier init_attr->event_handler = srp_qp_event; 240aef9ec39SRoland Dreier init_attr->cap.max_send_wr = SRP_SQ_SIZE; 241aef9ec39SRoland Dreier init_attr->cap.max_recv_wr = SRP_RQ_SIZE; 242aef9ec39SRoland Dreier init_attr->cap.max_recv_sge = 1; 243aef9ec39SRoland Dreier init_attr->cap.max_send_sge = 1; 244aef9ec39SRoland Dreier init_attr->sq_sig_type = IB_SIGNAL_ALL_WR; 245aef9ec39SRoland Dreier init_attr->qp_type = IB_QPT_RC; 246aef9ec39SRoland Dreier init_attr->send_cq = target->cq; 247aef9ec39SRoland Dreier init_attr->recv_cq = target->cq; 248aef9ec39SRoland Dreier 24905321937SGreg Kroah-Hartman target->qp = ib_create_qp(target->srp_host->srp_dev->pd, init_attr); 250aef9ec39SRoland Dreier if (IS_ERR(target->qp)) { 251aef9ec39SRoland Dreier ret = PTR_ERR(target->qp); 252aef9ec39SRoland Dreier ib_destroy_cq(target->cq); 253aef9ec39SRoland Dreier goto out; 254aef9ec39SRoland Dreier } 255aef9ec39SRoland Dreier 256aef9ec39SRoland Dreier ret = srp_init_qp(target, target->qp); 257aef9ec39SRoland Dreier if (ret) { 258aef9ec39SRoland Dreier ib_destroy_qp(target->qp); 259aef9ec39SRoland Dreier ib_destroy_cq(target->cq); 260aef9ec39SRoland Dreier goto out; 261aef9ec39SRoland Dreier } 262aef9ec39SRoland Dreier 263aef9ec39SRoland Dreier out: 264aef9ec39SRoland Dreier kfree(init_attr); 265aef9ec39SRoland Dreier return ret; 266aef9ec39SRoland Dreier } 267aef9ec39SRoland Dreier 268aef9ec39SRoland Dreier static void srp_free_target_ib(struct srp_target_port *target) 269aef9ec39SRoland Dreier { 270aef9ec39SRoland Dreier int i; 271aef9ec39SRoland Dreier 272aef9ec39SRoland Dreier ib_destroy_qp(target->qp); 273aef9ec39SRoland Dreier ib_destroy_cq(target->cq); 274aef9ec39SRoland Dreier 275aef9ec39SRoland Dreier for (i = 0; i < SRP_RQ_SIZE; ++i) 276aef9ec39SRoland Dreier srp_free_iu(target->srp_host, target->rx_ring[i]); 277aef9ec39SRoland Dreier for (i = 0; i < SRP_SQ_SIZE + 1; ++i) 278aef9ec39SRoland Dreier srp_free_iu(target->srp_host, target->tx_ring[i]); 279aef9ec39SRoland Dreier } 280aef9ec39SRoland Dreier 281aef9ec39SRoland Dreier static void srp_path_rec_completion(int status, 282aef9ec39SRoland Dreier struct ib_sa_path_rec *pathrec, 283aef9ec39SRoland Dreier void *target_ptr) 284aef9ec39SRoland Dreier { 285aef9ec39SRoland Dreier struct srp_target_port *target = target_ptr; 286aef9ec39SRoland Dreier 287aef9ec39SRoland Dreier target->status = status; 288aef9ec39SRoland Dreier if (status) 2897aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 2907aa54bd7SDavid Dillow PFX "Got failed path rec status %d\n", status); 291aef9ec39SRoland Dreier else 292aef9ec39SRoland Dreier target->path = *pathrec; 293aef9ec39SRoland Dreier complete(&target->done); 294aef9ec39SRoland Dreier } 295aef9ec39SRoland Dreier 296aef9ec39SRoland Dreier static int srp_lookup_path(struct srp_target_port *target) 297aef9ec39SRoland Dreier { 298aef9ec39SRoland Dreier target->path.numb_path = 1; 299aef9ec39SRoland Dreier 300aef9ec39SRoland Dreier init_completion(&target->done); 301aef9ec39SRoland Dreier 302c1a0b23bSMichael S. Tsirkin target->path_query_id = ib_sa_path_rec_get(&srp_sa_client, 30305321937SGreg Kroah-Hartman target->srp_host->srp_dev->dev, 304aef9ec39SRoland Dreier target->srp_host->port, 305aef9ec39SRoland Dreier &target->path, 306247e020eSSean Hefty IB_SA_PATH_REC_SERVICE_ID | 307aef9ec39SRoland Dreier IB_SA_PATH_REC_DGID | 308aef9ec39SRoland Dreier IB_SA_PATH_REC_SGID | 309aef9ec39SRoland Dreier IB_SA_PATH_REC_NUMB_PATH | 310aef9ec39SRoland Dreier IB_SA_PATH_REC_PKEY, 311aef9ec39SRoland Dreier SRP_PATH_REC_TIMEOUT_MS, 312aef9ec39SRoland Dreier GFP_KERNEL, 313aef9ec39SRoland Dreier srp_path_rec_completion, 314aef9ec39SRoland Dreier target, &target->path_query); 315aef9ec39SRoland Dreier if (target->path_query_id < 0) 316aef9ec39SRoland Dreier return target->path_query_id; 317aef9ec39SRoland Dreier 318aef9ec39SRoland Dreier wait_for_completion(&target->done); 319aef9ec39SRoland Dreier 320aef9ec39SRoland Dreier if (target->status < 0) 3217aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 3227aa54bd7SDavid Dillow PFX "Path record query failed\n"); 323aef9ec39SRoland Dreier 324aef9ec39SRoland Dreier return target->status; 325aef9ec39SRoland Dreier } 326aef9ec39SRoland Dreier 327aef9ec39SRoland Dreier static int srp_send_req(struct srp_target_port *target) 328aef9ec39SRoland Dreier { 329aef9ec39SRoland Dreier struct { 330aef9ec39SRoland Dreier struct ib_cm_req_param param; 331aef9ec39SRoland Dreier struct srp_login_req priv; 332aef9ec39SRoland Dreier } *req = NULL; 333aef9ec39SRoland Dreier int status; 334aef9ec39SRoland Dreier 335aef9ec39SRoland Dreier req = kzalloc(sizeof *req, GFP_KERNEL); 336aef9ec39SRoland Dreier if (!req) 337aef9ec39SRoland Dreier return -ENOMEM; 338aef9ec39SRoland Dreier 339aef9ec39SRoland Dreier req->param.primary_path = &target->path; 340aef9ec39SRoland Dreier req->param.alternate_path = NULL; 341aef9ec39SRoland Dreier req->param.service_id = target->service_id; 342aef9ec39SRoland Dreier req->param.qp_num = target->qp->qp_num; 343aef9ec39SRoland Dreier req->param.qp_type = target->qp->qp_type; 344aef9ec39SRoland Dreier req->param.private_data = &req->priv; 345aef9ec39SRoland Dreier req->param.private_data_len = sizeof req->priv; 346aef9ec39SRoland Dreier req->param.flow_control = 1; 347aef9ec39SRoland Dreier 348aef9ec39SRoland Dreier get_random_bytes(&req->param.starting_psn, 4); 349aef9ec39SRoland Dreier req->param.starting_psn &= 0xffffff; 350aef9ec39SRoland Dreier 351aef9ec39SRoland Dreier /* 352aef9ec39SRoland Dreier * Pick some arbitrary defaults here; we could make these 353aef9ec39SRoland Dreier * module parameters if anyone cared about setting them. 354aef9ec39SRoland Dreier */ 355aef9ec39SRoland Dreier req->param.responder_resources = 4; 356aef9ec39SRoland Dreier req->param.remote_cm_response_timeout = 20; 357aef9ec39SRoland Dreier req->param.local_cm_response_timeout = 20; 358aef9ec39SRoland Dreier req->param.retry_count = 7; 359aef9ec39SRoland Dreier req->param.rnr_retry_count = 7; 360aef9ec39SRoland Dreier req->param.max_cm_retries = 15; 361aef9ec39SRoland Dreier 362aef9ec39SRoland Dreier req->priv.opcode = SRP_LOGIN_REQ; 363aef9ec39SRoland Dreier req->priv.tag = 0; 36474b0a15bSVu Pham req->priv.req_it_iu_len = cpu_to_be32(srp_max_iu_len); 365aef9ec39SRoland Dreier req->priv.req_buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT | 366aef9ec39SRoland Dreier SRP_BUF_FORMAT_INDIRECT); 3670c0450dbSRamachandra K /* 3680c0450dbSRamachandra K * In the published SRP specification (draft rev. 16a), the 3690c0450dbSRamachandra K * port identifier format is 8 bytes of ID extension followed 3700c0450dbSRamachandra K * by 8 bytes of GUID. Older drafts put the two halves in the 3710c0450dbSRamachandra K * opposite order, so that the GUID comes first. 3720c0450dbSRamachandra K * 3730c0450dbSRamachandra K * Targets conforming to these obsolete drafts can be 3740c0450dbSRamachandra K * recognized by the I/O Class they report. 3750c0450dbSRamachandra K */ 3760c0450dbSRamachandra K if (target->io_class == SRP_REV10_IB_IO_CLASS) { 3770c0450dbSRamachandra K memcpy(req->priv.initiator_port_id, 37801cb9bcbSIshai Rabinovitz &target->path.sgid.global.interface_id, 8); 3790c0450dbSRamachandra K memcpy(req->priv.initiator_port_id + 8, 38001cb9bcbSIshai Rabinovitz &target->initiator_ext, 8); 3810c0450dbSRamachandra K memcpy(req->priv.target_port_id, &target->ioc_guid, 8); 3820c0450dbSRamachandra K memcpy(req->priv.target_port_id + 8, &target->id_ext, 8); 3830c0450dbSRamachandra K } else { 3840c0450dbSRamachandra K memcpy(req->priv.initiator_port_id, 38501cb9bcbSIshai Rabinovitz &target->initiator_ext, 8); 38601cb9bcbSIshai Rabinovitz memcpy(req->priv.initiator_port_id + 8, 38701cb9bcbSIshai Rabinovitz &target->path.sgid.global.interface_id, 8); 3880c0450dbSRamachandra K memcpy(req->priv.target_port_id, &target->id_ext, 8); 3890c0450dbSRamachandra K memcpy(req->priv.target_port_id + 8, &target->ioc_guid, 8); 3900c0450dbSRamachandra K } 3910c0450dbSRamachandra K 392aef9ec39SRoland Dreier /* 393aef9ec39SRoland Dreier * Topspin/Cisco SRP targets will reject our login unless we 39401cb9bcbSIshai Rabinovitz * zero out the first 8 bytes of our initiator port ID and set 39501cb9bcbSIshai Rabinovitz * the second 8 bytes to the local node GUID. 396aef9ec39SRoland Dreier */ 3975d7cbfd6SRoland Dreier if (srp_target_is_topspin(target)) { 3987aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, target->scsi_host, 3997aa54bd7SDavid Dillow PFX "Topspin/Cisco initiator port ID workaround " 400aef9ec39SRoland Dreier "activated for target GUID %016llx\n", 401aef9ec39SRoland Dreier (unsigned long long) be64_to_cpu(target->ioc_guid)); 402aef9ec39SRoland Dreier memset(req->priv.initiator_port_id, 0, 8); 40301cb9bcbSIshai Rabinovitz memcpy(req->priv.initiator_port_id + 8, 40405321937SGreg Kroah-Hartman &target->srp_host->srp_dev->dev->node_guid, 8); 405aef9ec39SRoland Dreier } 406aef9ec39SRoland Dreier 407aef9ec39SRoland Dreier status = ib_send_cm_req(target->cm_id, &req->param); 408aef9ec39SRoland Dreier 409aef9ec39SRoland Dreier kfree(req); 410aef9ec39SRoland Dreier 411aef9ec39SRoland Dreier return status; 412aef9ec39SRoland Dreier } 413aef9ec39SRoland Dreier 414aef9ec39SRoland Dreier static void srp_disconnect_target(struct srp_target_port *target) 415aef9ec39SRoland Dreier { 416aef9ec39SRoland Dreier /* XXX should send SRP_I_LOGOUT request */ 417aef9ec39SRoland Dreier 418aef9ec39SRoland Dreier init_completion(&target->done); 419e6581056SRoland Dreier if (ib_send_cm_dreq(target->cm_id, NULL, 0)) { 4207aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, target->scsi_host, 4217aa54bd7SDavid Dillow PFX "Sending CM DREQ failed\n"); 422e6581056SRoland Dreier return; 423e6581056SRoland Dreier } 424aef9ec39SRoland Dreier wait_for_completion(&target->done); 425aef9ec39SRoland Dreier } 426aef9ec39SRoland Dreier 427c4028958SDavid Howells static void srp_remove_work(struct work_struct *work) 428aef9ec39SRoland Dreier { 429c4028958SDavid Howells struct srp_target_port *target = 430c4028958SDavid Howells container_of(work, struct srp_target_port, work); 431aef9ec39SRoland Dreier 432aef9ec39SRoland Dreier spin_lock_irq(target->scsi_host->host_lock); 433aef9ec39SRoland Dreier if (target->state != SRP_TARGET_DEAD) { 434aef9ec39SRoland Dreier spin_unlock_irq(target->scsi_host->host_lock); 435aef9ec39SRoland Dreier return; 436aef9ec39SRoland Dreier } 437aef9ec39SRoland Dreier target->state = SRP_TARGET_REMOVED; 438aef9ec39SRoland Dreier spin_unlock_irq(target->scsi_host->host_lock); 439aef9ec39SRoland Dreier 440b3589fd4SMatthew Wilcox spin_lock(&target->srp_host->target_lock); 441aef9ec39SRoland Dreier list_del(&target->list); 442b3589fd4SMatthew Wilcox spin_unlock(&target->srp_host->target_lock); 443aef9ec39SRoland Dreier 4443236822bSFUJITA Tomonori srp_remove_host(target->scsi_host); 445aef9ec39SRoland Dreier scsi_remove_host(target->scsi_host); 446aef9ec39SRoland Dreier ib_destroy_cm_id(target->cm_id); 447aef9ec39SRoland Dreier srp_free_target_ib(target); 448aef9ec39SRoland Dreier scsi_host_put(target->scsi_host); 449aef9ec39SRoland Dreier } 450aef9ec39SRoland Dreier 451aef9ec39SRoland Dreier static int srp_connect_target(struct srp_target_port *target) 452aef9ec39SRoland Dreier { 4539fe4bcf4SDavid Dillow int retries = 3; 454aef9ec39SRoland Dreier int ret; 455aef9ec39SRoland Dreier 456aef9ec39SRoland Dreier ret = srp_lookup_path(target); 457aef9ec39SRoland Dreier if (ret) 458aef9ec39SRoland Dreier return ret; 459aef9ec39SRoland Dreier 460aef9ec39SRoland Dreier while (1) { 461aef9ec39SRoland Dreier init_completion(&target->done); 462aef9ec39SRoland Dreier ret = srp_send_req(target); 463aef9ec39SRoland Dreier if (ret) 464aef9ec39SRoland Dreier return ret; 465aef9ec39SRoland Dreier wait_for_completion(&target->done); 466aef9ec39SRoland Dreier 467aef9ec39SRoland Dreier /* 468aef9ec39SRoland Dreier * The CM event handling code will set status to 469aef9ec39SRoland Dreier * SRP_PORT_REDIRECT if we get a port redirect REJ 470aef9ec39SRoland Dreier * back, or SRP_DLID_REDIRECT if we get a lid/qp 471aef9ec39SRoland Dreier * redirect REJ back. 472aef9ec39SRoland Dreier */ 473aef9ec39SRoland Dreier switch (target->status) { 474aef9ec39SRoland Dreier case 0: 475aef9ec39SRoland Dreier return 0; 476aef9ec39SRoland Dreier 477aef9ec39SRoland Dreier case SRP_PORT_REDIRECT: 478aef9ec39SRoland Dreier ret = srp_lookup_path(target); 479aef9ec39SRoland Dreier if (ret) 480aef9ec39SRoland Dreier return ret; 481aef9ec39SRoland Dreier break; 482aef9ec39SRoland Dreier 483aef9ec39SRoland Dreier case SRP_DLID_REDIRECT: 484aef9ec39SRoland Dreier break; 485aef9ec39SRoland Dreier 4869fe4bcf4SDavid Dillow case SRP_STALE_CONN: 4879fe4bcf4SDavid Dillow /* Our current CM id was stale, and is now in timewait. 4889fe4bcf4SDavid Dillow * Try to reconnect with a new one. 4899fe4bcf4SDavid Dillow */ 4909fe4bcf4SDavid Dillow if (!retries-- || srp_new_cm_id(target)) { 4919fe4bcf4SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX 4929fe4bcf4SDavid Dillow "giving up on stale connection\n"); 4939fe4bcf4SDavid Dillow target->status = -ECONNRESET; 4949fe4bcf4SDavid Dillow return target->status; 4959fe4bcf4SDavid Dillow } 4969fe4bcf4SDavid Dillow 4979fe4bcf4SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX 4989fe4bcf4SDavid Dillow "retrying stale connection\n"); 4999fe4bcf4SDavid Dillow break; 5009fe4bcf4SDavid Dillow 501aef9ec39SRoland Dreier default: 502aef9ec39SRoland Dreier return target->status; 503aef9ec39SRoland Dreier } 504aef9ec39SRoland Dreier } 505aef9ec39SRoland Dreier } 506aef9ec39SRoland Dreier 507d945e1dfSRoland Dreier static void srp_unmap_data(struct scsi_cmnd *scmnd, 508d945e1dfSRoland Dreier struct srp_target_port *target, 509d945e1dfSRoland Dreier struct srp_request *req) 510d945e1dfSRoland Dreier { 511bb350d1dSFUJITA Tomonori if (!scsi_sglist(scmnd) || 512d945e1dfSRoland Dreier (scmnd->sc_data_direction != DMA_TO_DEVICE && 513d945e1dfSRoland Dreier scmnd->sc_data_direction != DMA_FROM_DEVICE)) 514d945e1dfSRoland Dreier return; 515d945e1dfSRoland Dreier 516f5358a17SRoland Dreier if (req->fmr) { 517f5358a17SRoland Dreier ib_fmr_pool_unmap(req->fmr); 518f5358a17SRoland Dreier req->fmr = NULL; 519f5358a17SRoland Dreier } 520f5358a17SRoland Dreier 52105321937SGreg Kroah-Hartman ib_dma_unmap_sg(target->srp_host->srp_dev->dev, scsi_sglist(scmnd), 522bb350d1dSFUJITA Tomonori scsi_sg_count(scmnd), scmnd->sc_data_direction); 523d945e1dfSRoland Dreier } 524d945e1dfSRoland Dreier 525526b4caaSIshai Rabinovitz static void srp_remove_req(struct srp_target_port *target, struct srp_request *req) 526526b4caaSIshai Rabinovitz { 527526b4caaSIshai Rabinovitz srp_unmap_data(req->scmnd, target, req); 528526b4caaSIshai Rabinovitz list_move_tail(&req->list, &target->free_reqs); 529526b4caaSIshai Rabinovitz } 530526b4caaSIshai Rabinovitz 531526b4caaSIshai Rabinovitz static void srp_reset_req(struct srp_target_port *target, struct srp_request *req) 532526b4caaSIshai Rabinovitz { 533526b4caaSIshai Rabinovitz req->scmnd->result = DID_RESET << 16; 534526b4caaSIshai Rabinovitz req->scmnd->scsi_done(req->scmnd); 535526b4caaSIshai Rabinovitz srp_remove_req(target, req); 536526b4caaSIshai Rabinovitz } 537526b4caaSIshai Rabinovitz 538aef9ec39SRoland Dreier static int srp_reconnect_target(struct srp_target_port *target) 539aef9ec39SRoland Dreier { 540aef9ec39SRoland Dreier struct ib_qp_attr qp_attr; 541526b4caaSIshai Rabinovitz struct srp_request *req, *tmp; 542aef9ec39SRoland Dreier struct ib_wc wc; 543aef9ec39SRoland Dreier int ret; 544aef9ec39SRoland Dreier 545aef9ec39SRoland Dreier spin_lock_irq(target->scsi_host->host_lock); 546aef9ec39SRoland Dreier if (target->state != SRP_TARGET_LIVE) { 547aef9ec39SRoland Dreier spin_unlock_irq(target->scsi_host->host_lock); 548aef9ec39SRoland Dreier return -EAGAIN; 549aef9ec39SRoland Dreier } 550aef9ec39SRoland Dreier target->state = SRP_TARGET_CONNECTING; 551aef9ec39SRoland Dreier spin_unlock_irq(target->scsi_host->host_lock); 552aef9ec39SRoland Dreier 553aef9ec39SRoland Dreier srp_disconnect_target(target); 554aef9ec39SRoland Dreier /* 555aef9ec39SRoland Dreier * Now get a new local CM ID so that we avoid confusing the 556aef9ec39SRoland Dreier * target in case things are really fouled up. 557aef9ec39SRoland Dreier */ 5589fe4bcf4SDavid Dillow ret = srp_new_cm_id(target); 5599fe4bcf4SDavid Dillow if (ret) 560aef9ec39SRoland Dreier goto err; 561aef9ec39SRoland Dreier 562aef9ec39SRoland Dreier qp_attr.qp_state = IB_QPS_RESET; 563aef9ec39SRoland Dreier ret = ib_modify_qp(target->qp, &qp_attr, IB_QP_STATE); 564aef9ec39SRoland Dreier if (ret) 565aef9ec39SRoland Dreier goto err; 566aef9ec39SRoland Dreier 567aef9ec39SRoland Dreier ret = srp_init_qp(target, target->qp); 568aef9ec39SRoland Dreier if (ret) 569aef9ec39SRoland Dreier goto err; 570aef9ec39SRoland Dreier 571aef9ec39SRoland Dreier while (ib_poll_cq(target->cq, 1, &wc) > 0) 572aef9ec39SRoland Dreier ; /* nothing */ 573aef9ec39SRoland Dreier 574d916a8f1SIshai Rabinovitz spin_lock_irq(target->scsi_host->host_lock); 575526b4caaSIshai Rabinovitz list_for_each_entry_safe(req, tmp, &target->req_queue, list) 576526b4caaSIshai Rabinovitz srp_reset_req(target, req); 577d916a8f1SIshai Rabinovitz spin_unlock_irq(target->scsi_host->host_lock); 578aef9ec39SRoland Dreier 579aef9ec39SRoland Dreier target->rx_head = 0; 580aef9ec39SRoland Dreier target->tx_head = 0; 581aef9ec39SRoland Dreier target->tx_tail = 0; 582aef9ec39SRoland Dreier 5831033ff67SIshai Rabinovitz target->qp_in_error = 0; 584aef9ec39SRoland Dreier ret = srp_connect_target(target); 585aef9ec39SRoland Dreier if (ret) 586aef9ec39SRoland Dreier goto err; 587aef9ec39SRoland Dreier 588aef9ec39SRoland Dreier spin_lock_irq(target->scsi_host->host_lock); 589aef9ec39SRoland Dreier if (target->state == SRP_TARGET_CONNECTING) { 590aef9ec39SRoland Dreier ret = 0; 591aef9ec39SRoland Dreier target->state = SRP_TARGET_LIVE; 592aef9ec39SRoland Dreier } else 593aef9ec39SRoland Dreier ret = -EAGAIN; 594aef9ec39SRoland Dreier spin_unlock_irq(target->scsi_host->host_lock); 595aef9ec39SRoland Dreier 596aef9ec39SRoland Dreier return ret; 597aef9ec39SRoland Dreier 598aef9ec39SRoland Dreier err: 5997aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 6007aa54bd7SDavid Dillow PFX "reconnect failed (%d), removing target port.\n", ret); 601aef9ec39SRoland Dreier 602aef9ec39SRoland Dreier /* 603aef9ec39SRoland Dreier * We couldn't reconnect, so kill our target port off. 604aef9ec39SRoland Dreier * However, we have to defer the real removal because we might 605aef9ec39SRoland Dreier * be in the context of the SCSI error handler now, which 606aef9ec39SRoland Dreier * would deadlock if we call scsi_remove_host(). 607aef9ec39SRoland Dreier */ 608aef9ec39SRoland Dreier spin_lock_irq(target->scsi_host->host_lock); 609aef9ec39SRoland Dreier if (target->state == SRP_TARGET_CONNECTING) { 610aef9ec39SRoland Dreier target->state = SRP_TARGET_DEAD; 611c4028958SDavid Howells INIT_WORK(&target->work, srp_remove_work); 612aef9ec39SRoland Dreier schedule_work(&target->work); 613aef9ec39SRoland Dreier } 614aef9ec39SRoland Dreier spin_unlock_irq(target->scsi_host->host_lock); 615aef9ec39SRoland Dreier 616aef9ec39SRoland Dreier return ret; 617aef9ec39SRoland Dreier } 618aef9ec39SRoland Dreier 619559ce8f1SIshai Rabinovitz static int srp_map_fmr(struct srp_target_port *target, struct scatterlist *scat, 620f5358a17SRoland Dreier int sg_cnt, struct srp_request *req, 621f5358a17SRoland Dreier struct srp_direct_buf *buf) 622f5358a17SRoland Dreier { 623f5358a17SRoland Dreier u64 io_addr = 0; 624f5358a17SRoland Dreier u64 *dma_pages; 625f5358a17SRoland Dreier u32 len; 626f5358a17SRoland Dreier int page_cnt; 627f5358a17SRoland Dreier int i, j; 628f5358a17SRoland Dreier int ret; 62905321937SGreg Kroah-Hartman struct srp_device *dev = target->srp_host->srp_dev; 63085507bccSRalph Campbell struct ib_device *ibdev = dev->dev; 631bb350d1dSFUJITA Tomonori struct scatterlist *sg; 632f5358a17SRoland Dreier 633f5358a17SRoland Dreier if (!dev->fmr_pool) 634f5358a17SRoland Dreier return -ENODEV; 635f5358a17SRoland Dreier 6365d7cbfd6SRoland Dreier if (srp_target_is_mellanox(target) && 6375d7cbfd6SRoland Dreier (ib_sg_dma_address(ibdev, &scat[0]) & ~dev->fmr_page_mask)) 638559ce8f1SIshai Rabinovitz return -EINVAL; 639559ce8f1SIshai Rabinovitz 640f5358a17SRoland Dreier len = page_cnt = 0; 641bb350d1dSFUJITA Tomonori scsi_for_each_sg(req->scmnd, sg, sg_cnt, i) { 642bb350d1dSFUJITA Tomonori unsigned int dma_len = ib_sg_dma_len(ibdev, sg); 64385507bccSRalph Campbell 644bb350d1dSFUJITA Tomonori if (ib_sg_dma_address(ibdev, sg) & ~dev->fmr_page_mask) { 645f5358a17SRoland Dreier if (i > 0) 646f5358a17SRoland Dreier return -EINVAL; 647f5358a17SRoland Dreier else 648f5358a17SRoland Dreier ++page_cnt; 649f5358a17SRoland Dreier } 650bb350d1dSFUJITA Tomonori if ((ib_sg_dma_address(ibdev, sg) + dma_len) & 651f5358a17SRoland Dreier ~dev->fmr_page_mask) { 652f5358a17SRoland Dreier if (i < sg_cnt - 1) 653f5358a17SRoland Dreier return -EINVAL; 654f5358a17SRoland Dreier else 655f5358a17SRoland Dreier ++page_cnt; 656f5358a17SRoland Dreier } 657f5358a17SRoland Dreier 65885507bccSRalph Campbell len += dma_len; 659f5358a17SRoland Dreier } 660f5358a17SRoland Dreier 661f5358a17SRoland Dreier page_cnt += len >> dev->fmr_page_shift; 662f5358a17SRoland Dreier if (page_cnt > SRP_FMR_SIZE) 663f5358a17SRoland Dreier return -ENOMEM; 664f5358a17SRoland Dreier 665f5358a17SRoland Dreier dma_pages = kmalloc(sizeof (u64) * page_cnt, GFP_ATOMIC); 666f5358a17SRoland Dreier if (!dma_pages) 667f5358a17SRoland Dreier return -ENOMEM; 668f5358a17SRoland Dreier 669f5358a17SRoland Dreier page_cnt = 0; 670bb350d1dSFUJITA Tomonori scsi_for_each_sg(req->scmnd, sg, sg_cnt, i) { 671bb350d1dSFUJITA Tomonori unsigned int dma_len = ib_sg_dma_len(ibdev, sg); 67285507bccSRalph Campbell 67385507bccSRalph Campbell for (j = 0; j < dma_len; j += dev->fmr_page_size) 674f5358a17SRoland Dreier dma_pages[page_cnt++] = 675bb350d1dSFUJITA Tomonori (ib_sg_dma_address(ibdev, sg) & 67685507bccSRalph Campbell dev->fmr_page_mask) + j; 67785507bccSRalph Campbell } 678f5358a17SRoland Dreier 679f5358a17SRoland Dreier req->fmr = ib_fmr_pool_map_phys(dev->fmr_pool, 680adfaa888SMichael S. Tsirkin dma_pages, page_cnt, io_addr); 681f5358a17SRoland Dreier if (IS_ERR(req->fmr)) { 682f5358a17SRoland Dreier ret = PTR_ERR(req->fmr); 6836583eb3dSVu Pham req->fmr = NULL; 684f5358a17SRoland Dreier goto out; 685f5358a17SRoland Dreier } 686f5358a17SRoland Dreier 68785507bccSRalph Campbell buf->va = cpu_to_be64(ib_sg_dma_address(ibdev, &scat[0]) & 68885507bccSRalph Campbell ~dev->fmr_page_mask); 689f5358a17SRoland Dreier buf->key = cpu_to_be32(req->fmr->fmr->rkey); 690f5358a17SRoland Dreier buf->len = cpu_to_be32(len); 691f5358a17SRoland Dreier 692f5358a17SRoland Dreier ret = 0; 693f5358a17SRoland Dreier 694f5358a17SRoland Dreier out: 695f5358a17SRoland Dreier kfree(dma_pages); 696f5358a17SRoland Dreier 697f5358a17SRoland Dreier return ret; 698f5358a17SRoland Dreier } 699f5358a17SRoland Dreier 700aef9ec39SRoland Dreier static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target, 701aef9ec39SRoland Dreier struct srp_request *req) 702aef9ec39SRoland Dreier { 703cf368713SRoland Dreier struct scatterlist *scat; 704aef9ec39SRoland Dreier struct srp_cmd *cmd = req->cmd->buf; 705cf368713SRoland Dreier int len, nents, count; 706f5358a17SRoland Dreier u8 fmt = SRP_DATA_DESC_DIRECT; 70785507bccSRalph Campbell struct srp_device *dev; 70885507bccSRalph Campbell struct ib_device *ibdev; 709aef9ec39SRoland Dreier 710bb350d1dSFUJITA Tomonori if (!scsi_sglist(scmnd) || scmnd->sc_data_direction == DMA_NONE) 711aef9ec39SRoland Dreier return sizeof (struct srp_cmd); 712aef9ec39SRoland Dreier 713aef9ec39SRoland Dreier if (scmnd->sc_data_direction != DMA_FROM_DEVICE && 714aef9ec39SRoland Dreier scmnd->sc_data_direction != DMA_TO_DEVICE) { 7157aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 7167aa54bd7SDavid Dillow PFX "Unhandled data direction %d\n", 717aef9ec39SRoland Dreier scmnd->sc_data_direction); 718aef9ec39SRoland Dreier return -EINVAL; 719aef9ec39SRoland Dreier } 720aef9ec39SRoland Dreier 721bb350d1dSFUJITA Tomonori nents = scsi_sg_count(scmnd); 722bb350d1dSFUJITA Tomonori scat = scsi_sglist(scmnd); 723aef9ec39SRoland Dreier 72405321937SGreg Kroah-Hartman dev = target->srp_host->srp_dev; 72585507bccSRalph Campbell ibdev = dev->dev; 72685507bccSRalph Campbell 72785507bccSRalph Campbell count = ib_dma_map_sg(ibdev, scat, nents, scmnd->sc_data_direction); 728aef9ec39SRoland Dreier 729aef9ec39SRoland Dreier fmt = SRP_DATA_DESC_DIRECT; 730f5358a17SRoland Dreier len = sizeof (struct srp_cmd) + sizeof (struct srp_direct_buf); 731f5358a17SRoland Dreier 732f5358a17SRoland Dreier if (count == 1) { 733f5358a17SRoland Dreier /* 734f5358a17SRoland Dreier * The midlayer only generated a single gather/scatter 735f5358a17SRoland Dreier * entry, or DMA mapping coalesced everything to a 736f5358a17SRoland Dreier * single entry. So a direct descriptor along with 737f5358a17SRoland Dreier * the DMA MR suffices. 738f5358a17SRoland Dreier */ 739f5358a17SRoland Dreier struct srp_direct_buf *buf = (void *) cmd->add_data; 740aef9ec39SRoland Dreier 74185507bccSRalph Campbell buf->va = cpu_to_be64(ib_sg_dma_address(ibdev, scat)); 74285507bccSRalph Campbell buf->key = cpu_to_be32(dev->mr->rkey); 74385507bccSRalph Campbell buf->len = cpu_to_be32(ib_sg_dma_len(ibdev, scat)); 744559ce8f1SIshai Rabinovitz } else if (srp_map_fmr(target, scat, count, req, 745f5358a17SRoland Dreier (void *) cmd->add_data)) { 746f5358a17SRoland Dreier /* 747f5358a17SRoland Dreier * FMR mapping failed, and the scatterlist has more 748f5358a17SRoland Dreier * than one entry. Generate an indirect memory 749f5358a17SRoland Dreier * descriptor. 750f5358a17SRoland Dreier */ 751aef9ec39SRoland Dreier struct srp_indirect_buf *buf = (void *) cmd->add_data; 752bb350d1dSFUJITA Tomonori struct scatterlist *sg; 753aef9ec39SRoland Dreier u32 datalen = 0; 754f5358a17SRoland Dreier int i; 755aef9ec39SRoland Dreier 756aef9ec39SRoland Dreier fmt = SRP_DATA_DESC_INDIRECT; 757f5358a17SRoland Dreier len = sizeof (struct srp_cmd) + 758f5358a17SRoland Dreier sizeof (struct srp_indirect_buf) + 759f5358a17SRoland Dreier count * sizeof (struct srp_direct_buf); 760f5358a17SRoland Dreier 761bb350d1dSFUJITA Tomonori scsi_for_each_sg(scmnd, sg, count, i) { 762bb350d1dSFUJITA Tomonori unsigned int dma_len = ib_sg_dma_len(ibdev, sg); 76385507bccSRalph Campbell 764f5358a17SRoland Dreier buf->desc_list[i].va = 765bb350d1dSFUJITA Tomonori cpu_to_be64(ib_sg_dma_address(ibdev, sg)); 766f5358a17SRoland Dreier buf->desc_list[i].key = 76785507bccSRalph Campbell cpu_to_be32(dev->mr->rkey); 76885507bccSRalph Campbell buf->desc_list[i].len = cpu_to_be32(dma_len); 76985507bccSRalph Campbell datalen += dma_len; 770f5358a17SRoland Dreier } 771aef9ec39SRoland Dreier 772aef9ec39SRoland Dreier if (scmnd->sc_data_direction == DMA_TO_DEVICE) 773cf368713SRoland Dreier cmd->data_out_desc_cnt = count; 774aef9ec39SRoland Dreier else 775cf368713SRoland Dreier cmd->data_in_desc_cnt = count; 776aef9ec39SRoland Dreier 777f5358a17SRoland Dreier buf->table_desc.va = 778f5358a17SRoland Dreier cpu_to_be64(req->cmd->dma + sizeof *cmd + sizeof *buf); 779aef9ec39SRoland Dreier buf->table_desc.key = 78005321937SGreg Kroah-Hartman cpu_to_be32(target->srp_host->srp_dev->mr->rkey); 781aef9ec39SRoland Dreier buf->table_desc.len = 782cf368713SRoland Dreier cpu_to_be32(count * sizeof (struct srp_direct_buf)); 783aef9ec39SRoland Dreier 784aef9ec39SRoland Dreier buf->len = cpu_to_be32(datalen); 785aef9ec39SRoland Dreier } 786aef9ec39SRoland Dreier 787aef9ec39SRoland Dreier if (scmnd->sc_data_direction == DMA_TO_DEVICE) 788aef9ec39SRoland Dreier cmd->buf_fmt = fmt << 4; 789aef9ec39SRoland Dreier else 790aef9ec39SRoland Dreier cmd->buf_fmt = fmt; 791aef9ec39SRoland Dreier 792aef9ec39SRoland Dreier return len; 793aef9ec39SRoland Dreier } 794aef9ec39SRoland Dreier 795aef9ec39SRoland Dreier static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) 796aef9ec39SRoland Dreier { 797aef9ec39SRoland Dreier struct srp_request *req; 798aef9ec39SRoland Dreier struct scsi_cmnd *scmnd; 799aef9ec39SRoland Dreier unsigned long flags; 800aef9ec39SRoland Dreier s32 delta; 801aef9ec39SRoland Dreier 802aef9ec39SRoland Dreier delta = (s32) be32_to_cpu(rsp->req_lim_delta); 803aef9ec39SRoland Dreier 804aef9ec39SRoland Dreier spin_lock_irqsave(target->scsi_host->host_lock, flags); 805aef9ec39SRoland Dreier 806aef9ec39SRoland Dreier target->req_lim += delta; 807aef9ec39SRoland Dreier 808aef9ec39SRoland Dreier req = &target->req_ring[rsp->tag & ~SRP_TAG_TSK_MGMT]; 809aef9ec39SRoland Dreier 810aef9ec39SRoland Dreier if (unlikely(rsp->tag & SRP_TAG_TSK_MGMT)) { 811aef9ec39SRoland Dreier if (be32_to_cpu(rsp->resp_data_len) < 4) 812aef9ec39SRoland Dreier req->tsk_status = -1; 813aef9ec39SRoland Dreier else 814aef9ec39SRoland Dreier req->tsk_status = rsp->data[3]; 815aef9ec39SRoland Dreier complete(&req->done); 816aef9ec39SRoland Dreier } else { 817aef9ec39SRoland Dreier scmnd = req->scmnd; 818aef9ec39SRoland Dreier if (!scmnd) 8197aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 8207aa54bd7SDavid Dillow "Null scmnd for RSP w/tag %016llx\n", 821aef9ec39SRoland Dreier (unsigned long long) rsp->tag); 822aef9ec39SRoland Dreier scmnd->result = rsp->status; 823aef9ec39SRoland Dreier 824aef9ec39SRoland Dreier if (rsp->flags & SRP_RSP_FLAG_SNSVALID) { 825aef9ec39SRoland Dreier memcpy(scmnd->sense_buffer, rsp->data + 826aef9ec39SRoland Dreier be32_to_cpu(rsp->resp_data_len), 827aef9ec39SRoland Dreier min_t(int, be32_to_cpu(rsp->sense_data_len), 828aef9ec39SRoland Dreier SCSI_SENSE_BUFFERSIZE)); 829aef9ec39SRoland Dreier } 830aef9ec39SRoland Dreier 831aef9ec39SRoland Dreier if (rsp->flags & (SRP_RSP_FLAG_DOOVER | SRP_RSP_FLAG_DOUNDER)) 832bb350d1dSFUJITA Tomonori scsi_set_resid(scmnd, be32_to_cpu(rsp->data_out_res_cnt)); 833aef9ec39SRoland Dreier else if (rsp->flags & (SRP_RSP_FLAG_DIOVER | SRP_RSP_FLAG_DIUNDER)) 834bb350d1dSFUJITA Tomonori scsi_set_resid(scmnd, be32_to_cpu(rsp->data_in_res_cnt)); 835aef9ec39SRoland Dreier 836aef9ec39SRoland Dreier if (!req->tsk_mgmt) { 837aef9ec39SRoland Dreier scmnd->host_scribble = (void *) -1L; 838aef9ec39SRoland Dreier scmnd->scsi_done(scmnd); 839aef9ec39SRoland Dreier 840d945e1dfSRoland Dreier srp_remove_req(target, req); 841aef9ec39SRoland Dreier } else 842aef9ec39SRoland Dreier req->cmd_done = 1; 843aef9ec39SRoland Dreier } 844aef9ec39SRoland Dreier 845aef9ec39SRoland Dreier spin_unlock_irqrestore(target->scsi_host->host_lock, flags); 846aef9ec39SRoland Dreier } 847aef9ec39SRoland Dreier 848aef9ec39SRoland Dreier static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc) 849aef9ec39SRoland Dreier { 85085507bccSRalph Campbell struct ib_device *dev; 851aef9ec39SRoland Dreier struct srp_iu *iu; 852aef9ec39SRoland Dreier u8 opcode; 853aef9ec39SRoland Dreier 854aef9ec39SRoland Dreier iu = target->rx_ring[wc->wr_id & ~SRP_OP_RECV]; 855aef9ec39SRoland Dreier 85605321937SGreg Kroah-Hartman dev = target->srp_host->srp_dev->dev; 85785507bccSRalph Campbell ib_dma_sync_single_for_cpu(dev, iu->dma, target->max_ti_iu_len, 85885507bccSRalph Campbell DMA_FROM_DEVICE); 859aef9ec39SRoland Dreier 860aef9ec39SRoland Dreier opcode = *(u8 *) iu->buf; 861aef9ec39SRoland Dreier 862aef9ec39SRoland Dreier if (0) { 863aef9ec39SRoland Dreier int i; 864aef9ec39SRoland Dreier 8657aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 8667aa54bd7SDavid Dillow PFX "recv completion, opcode 0x%02x\n", opcode); 867aef9ec39SRoland Dreier 868aef9ec39SRoland Dreier for (i = 0; i < wc->byte_len; ++i) { 869aef9ec39SRoland Dreier if (i % 8 == 0) 870aef9ec39SRoland Dreier printk(KERN_ERR " [%02x] ", i); 871aef9ec39SRoland Dreier printk(" %02x", ((u8 *) iu->buf)[i]); 872aef9ec39SRoland Dreier if ((i + 1) % 8 == 0) 873aef9ec39SRoland Dreier printk("\n"); 874aef9ec39SRoland Dreier } 875aef9ec39SRoland Dreier 876aef9ec39SRoland Dreier if (wc->byte_len % 8) 877aef9ec39SRoland Dreier printk("\n"); 878aef9ec39SRoland Dreier } 879aef9ec39SRoland Dreier 880aef9ec39SRoland Dreier switch (opcode) { 881aef9ec39SRoland Dreier case SRP_RSP: 882aef9ec39SRoland Dreier srp_process_rsp(target, iu->buf); 883aef9ec39SRoland Dreier break; 884aef9ec39SRoland Dreier 885aef9ec39SRoland Dreier case SRP_T_LOGOUT: 886aef9ec39SRoland Dreier /* XXX Handle target logout */ 8877aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 8887aa54bd7SDavid Dillow PFX "Got target logout request\n"); 889aef9ec39SRoland Dreier break; 890aef9ec39SRoland Dreier 891aef9ec39SRoland Dreier default: 8927aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 8937aa54bd7SDavid Dillow PFX "Unhandled SRP opcode 0x%02x\n", opcode); 894aef9ec39SRoland Dreier break; 895aef9ec39SRoland Dreier } 896aef9ec39SRoland Dreier 89785507bccSRalph Campbell ib_dma_sync_single_for_device(dev, iu->dma, target->max_ti_iu_len, 89885507bccSRalph Campbell DMA_FROM_DEVICE); 899aef9ec39SRoland Dreier } 900aef9ec39SRoland Dreier 901aef9ec39SRoland Dreier static void srp_completion(struct ib_cq *cq, void *target_ptr) 902aef9ec39SRoland Dreier { 903aef9ec39SRoland Dreier struct srp_target_port *target = target_ptr; 904aef9ec39SRoland Dreier struct ib_wc wc; 905aef9ec39SRoland Dreier 906aef9ec39SRoland Dreier ib_req_notify_cq(cq, IB_CQ_NEXT_COMP); 907aef9ec39SRoland Dreier while (ib_poll_cq(cq, 1, &wc) > 0) { 908aef9ec39SRoland Dreier if (wc.status) { 9097aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 9107aa54bd7SDavid Dillow PFX "failed %s status %d\n", 911aef9ec39SRoland Dreier wc.wr_id & SRP_OP_RECV ? "receive" : "send", 912aef9ec39SRoland Dreier wc.status); 9131033ff67SIshai Rabinovitz target->qp_in_error = 1; 914aef9ec39SRoland Dreier break; 915aef9ec39SRoland Dreier } 916aef9ec39SRoland Dreier 917aef9ec39SRoland Dreier if (wc.wr_id & SRP_OP_RECV) 918aef9ec39SRoland Dreier srp_handle_recv(target, &wc); 919aef9ec39SRoland Dreier else 920aef9ec39SRoland Dreier ++target->tx_tail; 921aef9ec39SRoland Dreier } 922aef9ec39SRoland Dreier } 923aef9ec39SRoland Dreier 924aef9ec39SRoland Dreier static int __srp_post_recv(struct srp_target_port *target) 925aef9ec39SRoland Dreier { 926aef9ec39SRoland Dreier struct srp_iu *iu; 927aef9ec39SRoland Dreier struct ib_sge list; 928aef9ec39SRoland Dreier struct ib_recv_wr wr, *bad_wr; 929aef9ec39SRoland Dreier unsigned int next; 930aef9ec39SRoland Dreier int ret; 931aef9ec39SRoland Dreier 932aef9ec39SRoland Dreier next = target->rx_head & (SRP_RQ_SIZE - 1); 933aef9ec39SRoland Dreier wr.wr_id = next | SRP_OP_RECV; 934aef9ec39SRoland Dreier iu = target->rx_ring[next]; 935aef9ec39SRoland Dreier 936aef9ec39SRoland Dreier list.addr = iu->dma; 937aef9ec39SRoland Dreier list.length = iu->size; 93805321937SGreg Kroah-Hartman list.lkey = target->srp_host->srp_dev->mr->lkey; 939aef9ec39SRoland Dreier 940aef9ec39SRoland Dreier wr.next = NULL; 941aef9ec39SRoland Dreier wr.sg_list = &list; 942aef9ec39SRoland Dreier wr.num_sge = 1; 943aef9ec39SRoland Dreier 944aef9ec39SRoland Dreier ret = ib_post_recv(target->qp, &wr, &bad_wr); 945aef9ec39SRoland Dreier if (!ret) 946aef9ec39SRoland Dreier ++target->rx_head; 947aef9ec39SRoland Dreier 948aef9ec39SRoland Dreier return ret; 949aef9ec39SRoland Dreier } 950aef9ec39SRoland Dreier 951aef9ec39SRoland Dreier static int srp_post_recv(struct srp_target_port *target) 952aef9ec39SRoland Dreier { 953aef9ec39SRoland Dreier unsigned long flags; 954aef9ec39SRoland Dreier int ret; 955aef9ec39SRoland Dreier 956aef9ec39SRoland Dreier spin_lock_irqsave(target->scsi_host->host_lock, flags); 957aef9ec39SRoland Dreier ret = __srp_post_recv(target); 958aef9ec39SRoland Dreier spin_unlock_irqrestore(target->scsi_host->host_lock, flags); 959aef9ec39SRoland Dreier 960aef9ec39SRoland Dreier return ret; 961aef9ec39SRoland Dreier } 962aef9ec39SRoland Dreier 963aef9ec39SRoland Dreier /* 964aef9ec39SRoland Dreier * Must be called with target->scsi_host->host_lock held to protect 96547f2bce9SRoland Dreier * req_lim and tx_head. Lock cannot be dropped between call here and 96647f2bce9SRoland Dreier * call to __srp_post_send(). 967aef9ec39SRoland Dreier */ 9688cba2077SDavid Dillow static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target, 9698cba2077SDavid Dillow enum srp_request_type req_type) 970aef9ec39SRoland Dreier { 9718cba2077SDavid Dillow s32 min = (req_type == SRP_REQ_TASK_MGMT) ? 1 : 2; 9728cba2077SDavid Dillow 973aef9ec39SRoland Dreier if (target->tx_head - target->tx_tail >= SRP_SQ_SIZE) 974aef9ec39SRoland Dreier return NULL; 975aef9ec39SRoland Dreier 9768cba2077SDavid Dillow if (target->req_lim < min) { 9776bfa24faSRoland Dreier ++target->zero_req_lim; 9788cba2077SDavid Dillow return NULL; 9798cba2077SDavid Dillow } 98047f2bce9SRoland Dreier 981aef9ec39SRoland Dreier return target->tx_ring[target->tx_head & SRP_SQ_SIZE]; 982aef9ec39SRoland Dreier } 983aef9ec39SRoland Dreier 984aef9ec39SRoland Dreier /* 985aef9ec39SRoland Dreier * Must be called with target->scsi_host->host_lock held to protect 986aef9ec39SRoland Dreier * req_lim and tx_head. 987aef9ec39SRoland Dreier */ 988aef9ec39SRoland Dreier static int __srp_post_send(struct srp_target_port *target, 989aef9ec39SRoland Dreier struct srp_iu *iu, int len) 990aef9ec39SRoland Dreier { 991aef9ec39SRoland Dreier struct ib_sge list; 992aef9ec39SRoland Dreier struct ib_send_wr wr, *bad_wr; 993aef9ec39SRoland Dreier int ret = 0; 994aef9ec39SRoland Dreier 995aef9ec39SRoland Dreier list.addr = iu->dma; 996aef9ec39SRoland Dreier list.length = len; 99705321937SGreg Kroah-Hartman list.lkey = target->srp_host->srp_dev->mr->lkey; 998aef9ec39SRoland Dreier 999aef9ec39SRoland Dreier wr.next = NULL; 1000aef9ec39SRoland Dreier wr.wr_id = target->tx_head & SRP_SQ_SIZE; 1001aef9ec39SRoland Dreier wr.sg_list = &list; 1002aef9ec39SRoland Dreier wr.num_sge = 1; 1003aef9ec39SRoland Dreier wr.opcode = IB_WR_SEND; 1004aef9ec39SRoland Dreier wr.send_flags = IB_SEND_SIGNALED; 1005aef9ec39SRoland Dreier 1006aef9ec39SRoland Dreier ret = ib_post_send(target->qp, &wr, &bad_wr); 1007aef9ec39SRoland Dreier 1008aef9ec39SRoland Dreier if (!ret) { 1009aef9ec39SRoland Dreier ++target->tx_head; 1010aef9ec39SRoland Dreier --target->req_lim; 1011aef9ec39SRoland Dreier } 1012aef9ec39SRoland Dreier 1013aef9ec39SRoland Dreier return ret; 1014aef9ec39SRoland Dreier } 1015aef9ec39SRoland Dreier 1016aef9ec39SRoland Dreier static int srp_queuecommand(struct scsi_cmnd *scmnd, 1017aef9ec39SRoland Dreier void (*done)(struct scsi_cmnd *)) 1018aef9ec39SRoland Dreier { 1019aef9ec39SRoland Dreier struct srp_target_port *target = host_to_target(scmnd->device->host); 1020aef9ec39SRoland Dreier struct srp_request *req; 1021aef9ec39SRoland Dreier struct srp_iu *iu; 1022aef9ec39SRoland Dreier struct srp_cmd *cmd; 102385507bccSRalph Campbell struct ib_device *dev; 1024aef9ec39SRoland Dreier int len; 1025aef9ec39SRoland Dreier 1026aef9ec39SRoland Dreier if (target->state == SRP_TARGET_CONNECTING) 1027aef9ec39SRoland Dreier goto err; 1028aef9ec39SRoland Dreier 1029aef9ec39SRoland Dreier if (target->state == SRP_TARGET_DEAD || 1030aef9ec39SRoland Dreier target->state == SRP_TARGET_REMOVED) { 1031aef9ec39SRoland Dreier scmnd->result = DID_BAD_TARGET << 16; 1032aef9ec39SRoland Dreier done(scmnd); 1033aef9ec39SRoland Dreier return 0; 1034aef9ec39SRoland Dreier } 1035aef9ec39SRoland Dreier 10368cba2077SDavid Dillow iu = __srp_get_tx_iu(target, SRP_REQ_NORMAL); 1037aef9ec39SRoland Dreier if (!iu) 1038aef9ec39SRoland Dreier goto err; 1039aef9ec39SRoland Dreier 104005321937SGreg Kroah-Hartman dev = target->srp_host->srp_dev->dev; 104185507bccSRalph Campbell ib_dma_sync_single_for_cpu(dev, iu->dma, srp_max_iu_len, 104285507bccSRalph Campbell DMA_TO_DEVICE); 1043aef9ec39SRoland Dreier 1044d945e1dfSRoland Dreier req = list_entry(target->free_reqs.next, struct srp_request, list); 1045aef9ec39SRoland Dreier 1046aef9ec39SRoland Dreier scmnd->scsi_done = done; 1047aef9ec39SRoland Dreier scmnd->result = 0; 1048d945e1dfSRoland Dreier scmnd->host_scribble = (void *) (long) req->index; 1049aef9ec39SRoland Dreier 1050aef9ec39SRoland Dreier cmd = iu->buf; 1051aef9ec39SRoland Dreier memset(cmd, 0, sizeof *cmd); 1052aef9ec39SRoland Dreier 1053aef9ec39SRoland Dreier cmd->opcode = SRP_CMD; 1054aef9ec39SRoland Dreier cmd->lun = cpu_to_be64((u64) scmnd->device->lun << 48); 1055d945e1dfSRoland Dreier cmd->tag = req->index; 1056aef9ec39SRoland Dreier memcpy(cmd->cdb, scmnd->cmnd, scmnd->cmd_len); 1057aef9ec39SRoland Dreier 1058aef9ec39SRoland Dreier req->scmnd = scmnd; 1059aef9ec39SRoland Dreier req->cmd = iu; 1060aef9ec39SRoland Dreier req->cmd_done = 0; 1061aef9ec39SRoland Dreier req->tsk_mgmt = NULL; 1062aef9ec39SRoland Dreier 1063aef9ec39SRoland Dreier len = srp_map_data(scmnd, target, req); 1064aef9ec39SRoland Dreier if (len < 0) { 10657aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 10667aa54bd7SDavid Dillow PFX "Failed to map data\n"); 1067aef9ec39SRoland Dreier goto err; 1068aef9ec39SRoland Dreier } 1069aef9ec39SRoland Dreier 1070aef9ec39SRoland Dreier if (__srp_post_recv(target)) { 10717aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX "Recv failed\n"); 1072aef9ec39SRoland Dreier goto err_unmap; 1073aef9ec39SRoland Dreier } 1074aef9ec39SRoland Dreier 107585507bccSRalph Campbell ib_dma_sync_single_for_device(dev, iu->dma, srp_max_iu_len, 107685507bccSRalph Campbell DMA_TO_DEVICE); 1077aef9ec39SRoland Dreier 1078aef9ec39SRoland Dreier if (__srp_post_send(target, iu, len)) { 10797aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX "Send failed\n"); 1080aef9ec39SRoland Dreier goto err_unmap; 1081aef9ec39SRoland Dreier } 1082aef9ec39SRoland Dreier 1083d945e1dfSRoland Dreier list_move_tail(&req->list, &target->req_queue); 1084aef9ec39SRoland Dreier 1085aef9ec39SRoland Dreier return 0; 1086aef9ec39SRoland Dreier 1087aef9ec39SRoland Dreier err_unmap: 1088aef9ec39SRoland Dreier srp_unmap_data(scmnd, target, req); 1089aef9ec39SRoland Dreier 1090aef9ec39SRoland Dreier err: 1091aef9ec39SRoland Dreier return SCSI_MLQUEUE_HOST_BUSY; 1092aef9ec39SRoland Dreier } 1093aef9ec39SRoland Dreier 1094aef9ec39SRoland Dreier static int srp_alloc_iu_bufs(struct srp_target_port *target) 1095aef9ec39SRoland Dreier { 1096aef9ec39SRoland Dreier int i; 1097aef9ec39SRoland Dreier 1098aef9ec39SRoland Dreier for (i = 0; i < SRP_RQ_SIZE; ++i) { 1099aef9ec39SRoland Dreier target->rx_ring[i] = srp_alloc_iu(target->srp_host, 1100aef9ec39SRoland Dreier target->max_ti_iu_len, 1101aef9ec39SRoland Dreier GFP_KERNEL, DMA_FROM_DEVICE); 1102aef9ec39SRoland Dreier if (!target->rx_ring[i]) 1103aef9ec39SRoland Dreier goto err; 1104aef9ec39SRoland Dreier } 1105aef9ec39SRoland Dreier 1106aef9ec39SRoland Dreier for (i = 0; i < SRP_SQ_SIZE + 1; ++i) { 1107aef9ec39SRoland Dreier target->tx_ring[i] = srp_alloc_iu(target->srp_host, 110874b0a15bSVu Pham srp_max_iu_len, 1109aef9ec39SRoland Dreier GFP_KERNEL, DMA_TO_DEVICE); 1110aef9ec39SRoland Dreier if (!target->tx_ring[i]) 1111aef9ec39SRoland Dreier goto err; 1112aef9ec39SRoland Dreier } 1113aef9ec39SRoland Dreier 1114aef9ec39SRoland Dreier return 0; 1115aef9ec39SRoland Dreier 1116aef9ec39SRoland Dreier err: 1117aef9ec39SRoland Dreier for (i = 0; i < SRP_RQ_SIZE; ++i) { 1118aef9ec39SRoland Dreier srp_free_iu(target->srp_host, target->rx_ring[i]); 1119aef9ec39SRoland Dreier target->rx_ring[i] = NULL; 1120aef9ec39SRoland Dreier } 1121aef9ec39SRoland Dreier 1122aef9ec39SRoland Dreier for (i = 0; i < SRP_SQ_SIZE + 1; ++i) { 1123aef9ec39SRoland Dreier srp_free_iu(target->srp_host, target->tx_ring[i]); 1124aef9ec39SRoland Dreier target->tx_ring[i] = NULL; 1125aef9ec39SRoland Dreier } 1126aef9ec39SRoland Dreier 1127aef9ec39SRoland Dreier return -ENOMEM; 1128aef9ec39SRoland Dreier } 1129aef9ec39SRoland Dreier 1130aef9ec39SRoland Dreier static void srp_cm_rej_handler(struct ib_cm_id *cm_id, 1131aef9ec39SRoland Dreier struct ib_cm_event *event, 1132aef9ec39SRoland Dreier struct srp_target_port *target) 1133aef9ec39SRoland Dreier { 11347aa54bd7SDavid Dillow struct Scsi_Host *shost = target->scsi_host; 1135aef9ec39SRoland Dreier struct ib_class_port_info *cpi; 1136aef9ec39SRoland Dreier int opcode; 1137aef9ec39SRoland Dreier 1138aef9ec39SRoland Dreier switch (event->param.rej_rcvd.reason) { 1139aef9ec39SRoland Dreier case IB_CM_REJ_PORT_CM_REDIRECT: 1140aef9ec39SRoland Dreier cpi = event->param.rej_rcvd.ari; 1141aef9ec39SRoland Dreier target->path.dlid = cpi->redirect_lid; 1142aef9ec39SRoland Dreier target->path.pkey = cpi->redirect_pkey; 1143aef9ec39SRoland Dreier cm_id->remote_cm_qpn = be32_to_cpu(cpi->redirect_qp) & 0x00ffffff; 1144aef9ec39SRoland Dreier memcpy(target->path.dgid.raw, cpi->redirect_gid, 16); 1145aef9ec39SRoland Dreier 1146aef9ec39SRoland Dreier target->status = target->path.dlid ? 1147aef9ec39SRoland Dreier SRP_DLID_REDIRECT : SRP_PORT_REDIRECT; 1148aef9ec39SRoland Dreier break; 1149aef9ec39SRoland Dreier 1150aef9ec39SRoland Dreier case IB_CM_REJ_PORT_REDIRECT: 11515d7cbfd6SRoland Dreier if (srp_target_is_topspin(target)) { 1152aef9ec39SRoland Dreier /* 1153aef9ec39SRoland Dreier * Topspin/Cisco SRP gateways incorrectly send 1154aef9ec39SRoland Dreier * reject reason code 25 when they mean 24 1155aef9ec39SRoland Dreier * (port redirect). 1156aef9ec39SRoland Dreier */ 1157aef9ec39SRoland Dreier memcpy(target->path.dgid.raw, 1158aef9ec39SRoland Dreier event->param.rej_rcvd.ari, 16); 1159aef9ec39SRoland Dreier 11607aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, shost, 11617aa54bd7SDavid Dillow PFX "Topspin/Cisco redirect to target port GID %016llx%016llx\n", 1162aef9ec39SRoland Dreier (unsigned long long) be64_to_cpu(target->path.dgid.global.subnet_prefix), 1163aef9ec39SRoland Dreier (unsigned long long) be64_to_cpu(target->path.dgid.global.interface_id)); 1164aef9ec39SRoland Dreier 1165aef9ec39SRoland Dreier target->status = SRP_PORT_REDIRECT; 1166aef9ec39SRoland Dreier } else { 11677aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, 11687aa54bd7SDavid Dillow " REJ reason: IB_CM_REJ_PORT_REDIRECT\n"); 1169aef9ec39SRoland Dreier target->status = -ECONNRESET; 1170aef9ec39SRoland Dreier } 1171aef9ec39SRoland Dreier break; 1172aef9ec39SRoland Dreier 1173aef9ec39SRoland Dreier case IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID: 11747aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, 11757aa54bd7SDavid Dillow " REJ reason: IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID\n"); 1176aef9ec39SRoland Dreier target->status = -ECONNRESET; 1177aef9ec39SRoland Dreier break; 1178aef9ec39SRoland Dreier 1179aef9ec39SRoland Dreier case IB_CM_REJ_CONSUMER_DEFINED: 1180aef9ec39SRoland Dreier opcode = *(u8 *) event->private_data; 1181aef9ec39SRoland Dreier if (opcode == SRP_LOGIN_REJ) { 1182aef9ec39SRoland Dreier struct srp_login_rej *rej = event->private_data; 1183aef9ec39SRoland Dreier u32 reason = be32_to_cpu(rej->reason); 1184aef9ec39SRoland Dreier 1185aef9ec39SRoland Dreier if (reason == SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE) 11867aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, 11877aa54bd7SDavid Dillow PFX "SRP_LOGIN_REJ: requested max_it_iu_len too large\n"); 1188aef9ec39SRoland Dreier else 11897aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, 11907aa54bd7SDavid Dillow PFX "SRP LOGIN REJECTED, reason 0x%08x\n", reason); 1191aef9ec39SRoland Dreier } else 11927aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, 11937aa54bd7SDavid Dillow " REJ reason: IB_CM_REJ_CONSUMER_DEFINED," 1194aef9ec39SRoland Dreier " opcode 0x%02x\n", opcode); 1195aef9ec39SRoland Dreier target->status = -ECONNRESET; 1196aef9ec39SRoland Dreier break; 1197aef9ec39SRoland Dreier 11989fe4bcf4SDavid Dillow case IB_CM_REJ_STALE_CONN: 11999fe4bcf4SDavid Dillow shost_printk(KERN_WARNING, shost, " REJ reason: stale connection\n"); 12009fe4bcf4SDavid Dillow target->status = SRP_STALE_CONN; 12019fe4bcf4SDavid Dillow break; 12029fe4bcf4SDavid Dillow 1203aef9ec39SRoland Dreier default: 12047aa54bd7SDavid Dillow shost_printk(KERN_WARNING, shost, " REJ reason 0x%x\n", 1205aef9ec39SRoland Dreier event->param.rej_rcvd.reason); 1206aef9ec39SRoland Dreier target->status = -ECONNRESET; 1207aef9ec39SRoland Dreier } 1208aef9ec39SRoland Dreier } 1209aef9ec39SRoland Dreier 1210aef9ec39SRoland Dreier static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) 1211aef9ec39SRoland Dreier { 1212aef9ec39SRoland Dreier struct srp_target_port *target = cm_id->context; 1213aef9ec39SRoland Dreier struct ib_qp_attr *qp_attr = NULL; 1214aef9ec39SRoland Dreier int attr_mask = 0; 1215aef9ec39SRoland Dreier int comp = 0; 1216aef9ec39SRoland Dreier int opcode = 0; 1217aef9ec39SRoland Dreier 1218aef9ec39SRoland Dreier switch (event->event) { 1219aef9ec39SRoland Dreier case IB_CM_REQ_ERROR: 12207aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, target->scsi_host, 12217aa54bd7SDavid Dillow PFX "Sending CM REQ failed\n"); 1222aef9ec39SRoland Dreier comp = 1; 1223aef9ec39SRoland Dreier target->status = -ECONNRESET; 1224aef9ec39SRoland Dreier break; 1225aef9ec39SRoland Dreier 1226aef9ec39SRoland Dreier case IB_CM_REP_RECEIVED: 1227aef9ec39SRoland Dreier comp = 1; 1228aef9ec39SRoland Dreier opcode = *(u8 *) event->private_data; 1229aef9ec39SRoland Dreier 1230aef9ec39SRoland Dreier if (opcode == SRP_LOGIN_RSP) { 1231aef9ec39SRoland Dreier struct srp_login_rsp *rsp = event->private_data; 1232aef9ec39SRoland Dreier 1233aef9ec39SRoland Dreier target->max_ti_iu_len = be32_to_cpu(rsp->max_ti_iu_len); 1234aef9ec39SRoland Dreier target->req_lim = be32_to_cpu(rsp->req_lim_delta); 1235aef9ec39SRoland Dreier 1236aef9ec39SRoland Dreier target->scsi_host->can_queue = min(target->req_lim, 1237aef9ec39SRoland Dreier target->scsi_host->can_queue); 1238aef9ec39SRoland Dreier } else { 12397aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 12407aa54bd7SDavid Dillow PFX "Unhandled RSP opcode %#x\n", opcode); 1241aef9ec39SRoland Dreier target->status = -ECONNRESET; 1242aef9ec39SRoland Dreier break; 1243aef9ec39SRoland Dreier } 1244aef9ec39SRoland Dreier 1245d2fcea7dSVu Pham if (!target->rx_ring[0]) { 1246aef9ec39SRoland Dreier target->status = srp_alloc_iu_bufs(target); 1247aef9ec39SRoland Dreier if (target->status) 1248aef9ec39SRoland Dreier break; 1249d2fcea7dSVu Pham } 1250aef9ec39SRoland Dreier 1251aef9ec39SRoland Dreier qp_attr = kmalloc(sizeof *qp_attr, GFP_KERNEL); 1252aef9ec39SRoland Dreier if (!qp_attr) { 1253aef9ec39SRoland Dreier target->status = -ENOMEM; 1254aef9ec39SRoland Dreier break; 1255aef9ec39SRoland Dreier } 1256aef9ec39SRoland Dreier 1257aef9ec39SRoland Dreier qp_attr->qp_state = IB_QPS_RTR; 1258aef9ec39SRoland Dreier target->status = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask); 1259aef9ec39SRoland Dreier if (target->status) 1260aef9ec39SRoland Dreier break; 1261aef9ec39SRoland Dreier 1262aef9ec39SRoland Dreier target->status = ib_modify_qp(target->qp, qp_attr, attr_mask); 1263aef9ec39SRoland Dreier if (target->status) 1264aef9ec39SRoland Dreier break; 1265aef9ec39SRoland Dreier 1266aef9ec39SRoland Dreier target->status = srp_post_recv(target); 1267aef9ec39SRoland Dreier if (target->status) 1268aef9ec39SRoland Dreier break; 1269aef9ec39SRoland Dreier 1270aef9ec39SRoland Dreier qp_attr->qp_state = IB_QPS_RTS; 1271aef9ec39SRoland Dreier target->status = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask); 1272aef9ec39SRoland Dreier if (target->status) 1273aef9ec39SRoland Dreier break; 1274aef9ec39SRoland Dreier 1275aef9ec39SRoland Dreier target->status = ib_modify_qp(target->qp, qp_attr, attr_mask); 1276aef9ec39SRoland Dreier if (target->status) 1277aef9ec39SRoland Dreier break; 1278aef9ec39SRoland Dreier 1279aef9ec39SRoland Dreier target->status = ib_send_cm_rtu(cm_id, NULL, 0); 1280aef9ec39SRoland Dreier if (target->status) 1281aef9ec39SRoland Dreier break; 1282aef9ec39SRoland Dreier 1283aef9ec39SRoland Dreier break; 1284aef9ec39SRoland Dreier 1285aef9ec39SRoland Dreier case IB_CM_REJ_RECEIVED: 12867aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, target->scsi_host, PFX "REJ received\n"); 1287aef9ec39SRoland Dreier comp = 1; 1288aef9ec39SRoland Dreier 1289aef9ec39SRoland Dreier srp_cm_rej_handler(cm_id, event, target); 1290aef9ec39SRoland Dreier break; 1291aef9ec39SRoland Dreier 1292b7ac4ab4SIshai Rabinovitz case IB_CM_DREQ_RECEIVED: 12937aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 12947aa54bd7SDavid Dillow PFX "DREQ received - connection closed\n"); 1295b7ac4ab4SIshai Rabinovitz if (ib_send_cm_drep(cm_id, NULL, 0)) 12967aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 12977aa54bd7SDavid Dillow PFX "Sending CM DREP failed\n"); 1298aef9ec39SRoland Dreier break; 1299aef9ec39SRoland Dreier 1300aef9ec39SRoland Dreier case IB_CM_TIMEWAIT_EXIT: 13017aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 13027aa54bd7SDavid Dillow PFX "connection closed\n"); 1303aef9ec39SRoland Dreier 1304aef9ec39SRoland Dreier comp = 1; 1305aef9ec39SRoland Dreier target->status = 0; 1306aef9ec39SRoland Dreier break; 1307aef9ec39SRoland Dreier 1308b7ac4ab4SIshai Rabinovitz case IB_CM_MRA_RECEIVED: 1309b7ac4ab4SIshai Rabinovitz case IB_CM_DREQ_ERROR: 1310b7ac4ab4SIshai Rabinovitz case IB_CM_DREP_RECEIVED: 1311b7ac4ab4SIshai Rabinovitz break; 1312b7ac4ab4SIshai Rabinovitz 1313aef9ec39SRoland Dreier default: 13147aa54bd7SDavid Dillow shost_printk(KERN_WARNING, target->scsi_host, 13157aa54bd7SDavid Dillow PFX "Unhandled CM event %d\n", event->event); 1316aef9ec39SRoland Dreier break; 1317aef9ec39SRoland Dreier } 1318aef9ec39SRoland Dreier 1319aef9ec39SRoland Dreier if (comp) 1320aef9ec39SRoland Dreier complete(&target->done); 1321aef9ec39SRoland Dreier 1322aef9ec39SRoland Dreier kfree(qp_attr); 1323aef9ec39SRoland Dreier 1324aef9ec39SRoland Dreier return 0; 1325aef9ec39SRoland Dreier } 1326aef9ec39SRoland Dreier 1327d945e1dfSRoland Dreier static int srp_send_tsk_mgmt(struct srp_target_port *target, 1328d945e1dfSRoland Dreier struct srp_request *req, u8 func) 1329aef9ec39SRoland Dreier { 1330aef9ec39SRoland Dreier struct srp_iu *iu; 1331aef9ec39SRoland Dreier struct srp_tsk_mgmt *tsk_mgmt; 1332aef9ec39SRoland Dreier 1333aef9ec39SRoland Dreier spin_lock_irq(target->scsi_host->host_lock); 1334aef9ec39SRoland Dreier 13351285b3a0SRoland Dreier if (target->state == SRP_TARGET_DEAD || 13361285b3a0SRoland Dreier target->state == SRP_TARGET_REMOVED) { 1337d945e1dfSRoland Dreier req->scmnd->result = DID_BAD_TARGET << 16; 13381285b3a0SRoland Dreier goto out; 13391285b3a0SRoland Dreier } 13401285b3a0SRoland Dreier 1341aef9ec39SRoland Dreier init_completion(&req->done); 1342aef9ec39SRoland Dreier 13438cba2077SDavid Dillow iu = __srp_get_tx_iu(target, SRP_REQ_TASK_MGMT); 1344aef9ec39SRoland Dreier if (!iu) 1345aef9ec39SRoland Dreier goto out; 1346aef9ec39SRoland Dreier 1347aef9ec39SRoland Dreier tsk_mgmt = iu->buf; 1348aef9ec39SRoland Dreier memset(tsk_mgmt, 0, sizeof *tsk_mgmt); 1349aef9ec39SRoland Dreier 1350aef9ec39SRoland Dreier tsk_mgmt->opcode = SRP_TSK_MGMT; 1351d945e1dfSRoland Dreier tsk_mgmt->lun = cpu_to_be64((u64) req->scmnd->device->lun << 48); 1352d945e1dfSRoland Dreier tsk_mgmt->tag = req->index | SRP_TAG_TSK_MGMT; 1353aef9ec39SRoland Dreier tsk_mgmt->tsk_mgmt_func = func; 1354d945e1dfSRoland Dreier tsk_mgmt->task_tag = req->index; 1355aef9ec39SRoland Dreier 1356aef9ec39SRoland Dreier if (__srp_post_send(target, iu, sizeof *tsk_mgmt)) 1357aef9ec39SRoland Dreier goto out; 1358aef9ec39SRoland Dreier 1359aef9ec39SRoland Dreier req->tsk_mgmt = iu; 1360aef9ec39SRoland Dreier 1361aef9ec39SRoland Dreier spin_unlock_irq(target->scsi_host->host_lock); 1362d945e1dfSRoland Dreier 1363aef9ec39SRoland Dreier if (!wait_for_completion_timeout(&req->done, 1364aef9ec39SRoland Dreier msecs_to_jiffies(SRP_ABORT_TIMEOUT_MS))) 1365d945e1dfSRoland Dreier return -1; 1366aef9ec39SRoland Dreier 1367d945e1dfSRoland Dreier return 0; 1368aef9ec39SRoland Dreier 1369aef9ec39SRoland Dreier out: 1370aef9ec39SRoland Dreier spin_unlock_irq(target->scsi_host->host_lock); 1371d945e1dfSRoland Dreier return -1; 1372d945e1dfSRoland Dreier } 1373d945e1dfSRoland Dreier 1374d945e1dfSRoland Dreier static int srp_find_req(struct srp_target_port *target, 1375d945e1dfSRoland Dreier struct scsi_cmnd *scmnd, 1376d945e1dfSRoland Dreier struct srp_request **req) 1377d945e1dfSRoland Dreier { 1378d945e1dfSRoland Dreier if (scmnd->host_scribble == (void *) -1L) 1379d945e1dfSRoland Dreier return -1; 1380d945e1dfSRoland Dreier 1381d945e1dfSRoland Dreier *req = &target->req_ring[(long) scmnd->host_scribble]; 1382d945e1dfSRoland Dreier 1383d945e1dfSRoland Dreier return 0; 1384aef9ec39SRoland Dreier } 1385aef9ec39SRoland Dreier 1386aef9ec39SRoland Dreier static int srp_abort(struct scsi_cmnd *scmnd) 1387aef9ec39SRoland Dreier { 1388d945e1dfSRoland Dreier struct srp_target_port *target = host_to_target(scmnd->device->host); 1389d945e1dfSRoland Dreier struct srp_request *req; 1390d945e1dfSRoland Dreier int ret = SUCCESS; 1391d945e1dfSRoland Dreier 13927aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n"); 1393aef9ec39SRoland Dreier 13941033ff67SIshai Rabinovitz if (target->qp_in_error) 13951033ff67SIshai Rabinovitz return FAILED; 1396d945e1dfSRoland Dreier if (srp_find_req(target, scmnd, &req)) 1397d945e1dfSRoland Dreier return FAILED; 1398d945e1dfSRoland Dreier if (srp_send_tsk_mgmt(target, req, SRP_TSK_ABORT_TASK)) 1399d945e1dfSRoland Dreier return FAILED; 1400d945e1dfSRoland Dreier 1401d945e1dfSRoland Dreier spin_lock_irq(target->scsi_host->host_lock); 1402d945e1dfSRoland Dreier 1403d945e1dfSRoland Dreier if (req->cmd_done) { 1404d945e1dfSRoland Dreier srp_remove_req(target, req); 1405d945e1dfSRoland Dreier scmnd->scsi_done(scmnd); 1406d945e1dfSRoland Dreier } else if (!req->tsk_status) { 1407d945e1dfSRoland Dreier srp_remove_req(target, req); 1408d945e1dfSRoland Dreier scmnd->result = DID_ABORT << 16; 1409d945e1dfSRoland Dreier } else 1410d945e1dfSRoland Dreier ret = FAILED; 1411d945e1dfSRoland Dreier 1412d945e1dfSRoland Dreier spin_unlock_irq(target->scsi_host->host_lock); 1413d945e1dfSRoland Dreier 1414d945e1dfSRoland Dreier return ret; 1415aef9ec39SRoland Dreier } 1416aef9ec39SRoland Dreier 1417aef9ec39SRoland Dreier static int srp_reset_device(struct scsi_cmnd *scmnd) 1418aef9ec39SRoland Dreier { 1419d945e1dfSRoland Dreier struct srp_target_port *target = host_to_target(scmnd->device->host); 1420d945e1dfSRoland Dreier struct srp_request *req, *tmp; 1421d945e1dfSRoland Dreier 14227aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, "SRP reset_device called\n"); 1423aef9ec39SRoland Dreier 14241033ff67SIshai Rabinovitz if (target->qp_in_error) 14251033ff67SIshai Rabinovitz return FAILED; 1426d945e1dfSRoland Dreier if (srp_find_req(target, scmnd, &req)) 1427d945e1dfSRoland Dreier return FAILED; 1428d945e1dfSRoland Dreier if (srp_send_tsk_mgmt(target, req, SRP_TSK_LUN_RESET)) 1429d945e1dfSRoland Dreier return FAILED; 1430d945e1dfSRoland Dreier if (req->tsk_status) 1431d945e1dfSRoland Dreier return FAILED; 1432d945e1dfSRoland Dreier 1433d945e1dfSRoland Dreier spin_lock_irq(target->scsi_host->host_lock); 1434d945e1dfSRoland Dreier 1435d945e1dfSRoland Dreier list_for_each_entry_safe(req, tmp, &target->req_queue, list) 1436526b4caaSIshai Rabinovitz if (req->scmnd->device == scmnd->device) 1437526b4caaSIshai Rabinovitz srp_reset_req(target, req); 1438d945e1dfSRoland Dreier 1439d945e1dfSRoland Dreier spin_unlock_irq(target->scsi_host->host_lock); 1440d945e1dfSRoland Dreier 1441d945e1dfSRoland Dreier return SUCCESS; 1442aef9ec39SRoland Dreier } 1443aef9ec39SRoland Dreier 1444aef9ec39SRoland Dreier static int srp_reset_host(struct scsi_cmnd *scmnd) 1445aef9ec39SRoland Dreier { 1446aef9ec39SRoland Dreier struct srp_target_port *target = host_to_target(scmnd->device->host); 1447aef9ec39SRoland Dreier int ret = FAILED; 1448aef9ec39SRoland Dreier 14497aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, PFX "SRP reset_host called\n"); 1450aef9ec39SRoland Dreier 1451aef9ec39SRoland Dreier if (!srp_reconnect_target(target)) 1452aef9ec39SRoland Dreier ret = SUCCESS; 1453aef9ec39SRoland Dreier 1454aef9ec39SRoland Dreier return ret; 1455aef9ec39SRoland Dreier } 1456aef9ec39SRoland Dreier 1457ee959b00STony Jones static ssize_t show_id_ext(struct device *dev, struct device_attribute *attr, 1458ee959b00STony Jones char *buf) 14596ecb0c84SRoland Dreier { 1460ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 14616ecb0c84SRoland Dreier 14626ecb0c84SRoland Dreier if (target->state == SRP_TARGET_DEAD || 14636ecb0c84SRoland Dreier target->state == SRP_TARGET_REMOVED) 14646ecb0c84SRoland Dreier return -ENODEV; 14656ecb0c84SRoland Dreier 14666ecb0c84SRoland Dreier return sprintf(buf, "0x%016llx\n", 14676ecb0c84SRoland Dreier (unsigned long long) be64_to_cpu(target->id_ext)); 14686ecb0c84SRoland Dreier } 14696ecb0c84SRoland Dreier 1470ee959b00STony Jones static ssize_t show_ioc_guid(struct device *dev, struct device_attribute *attr, 1471ee959b00STony Jones char *buf) 14726ecb0c84SRoland Dreier { 1473ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 14746ecb0c84SRoland Dreier 14756ecb0c84SRoland Dreier if (target->state == SRP_TARGET_DEAD || 14766ecb0c84SRoland Dreier target->state == SRP_TARGET_REMOVED) 14776ecb0c84SRoland Dreier return -ENODEV; 14786ecb0c84SRoland Dreier 14796ecb0c84SRoland Dreier return sprintf(buf, "0x%016llx\n", 14806ecb0c84SRoland Dreier (unsigned long long) be64_to_cpu(target->ioc_guid)); 14816ecb0c84SRoland Dreier } 14826ecb0c84SRoland Dreier 1483ee959b00STony Jones static ssize_t show_service_id(struct device *dev, 1484ee959b00STony Jones struct device_attribute *attr, char *buf) 14856ecb0c84SRoland Dreier { 1486ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 14876ecb0c84SRoland Dreier 14886ecb0c84SRoland Dreier if (target->state == SRP_TARGET_DEAD || 14896ecb0c84SRoland Dreier target->state == SRP_TARGET_REMOVED) 14906ecb0c84SRoland Dreier return -ENODEV; 14916ecb0c84SRoland Dreier 14926ecb0c84SRoland Dreier return sprintf(buf, "0x%016llx\n", 14936ecb0c84SRoland Dreier (unsigned long long) be64_to_cpu(target->service_id)); 14946ecb0c84SRoland Dreier } 14956ecb0c84SRoland Dreier 1496ee959b00STony Jones static ssize_t show_pkey(struct device *dev, struct device_attribute *attr, 1497ee959b00STony Jones char *buf) 14986ecb0c84SRoland Dreier { 1499ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 15006ecb0c84SRoland Dreier 15016ecb0c84SRoland Dreier if (target->state == SRP_TARGET_DEAD || 15026ecb0c84SRoland Dreier target->state == SRP_TARGET_REMOVED) 15036ecb0c84SRoland Dreier return -ENODEV; 15046ecb0c84SRoland Dreier 15056ecb0c84SRoland Dreier return sprintf(buf, "0x%04x\n", be16_to_cpu(target->path.pkey)); 15066ecb0c84SRoland Dreier } 15076ecb0c84SRoland Dreier 1508ee959b00STony Jones static ssize_t show_dgid(struct device *dev, struct device_attribute *attr, 1509ee959b00STony Jones char *buf) 15106ecb0c84SRoland Dreier { 1511ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 15126ecb0c84SRoland Dreier 15136ecb0c84SRoland Dreier if (target->state == SRP_TARGET_DEAD || 15146ecb0c84SRoland Dreier target->state == SRP_TARGET_REMOVED) 15156ecb0c84SRoland Dreier return -ENODEV; 15166ecb0c84SRoland Dreier 1517*8867cd7cSHarvey Harrison return sprintf(buf, "%p6\n", target->path.dgid.raw); 15186ecb0c84SRoland Dreier } 15196ecb0c84SRoland Dreier 1520ee959b00STony Jones static ssize_t show_orig_dgid(struct device *dev, 1521ee959b00STony Jones struct device_attribute *attr, char *buf) 15223633b3d0SIshai Rabinovitz { 1523ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 15243633b3d0SIshai Rabinovitz 15253633b3d0SIshai Rabinovitz if (target->state == SRP_TARGET_DEAD || 15263633b3d0SIshai Rabinovitz target->state == SRP_TARGET_REMOVED) 15273633b3d0SIshai Rabinovitz return -ENODEV; 15283633b3d0SIshai Rabinovitz 1529*8867cd7cSHarvey Harrison return sprintf(buf, "%p6\n", target->orig_dgid); 15303633b3d0SIshai Rabinovitz } 15313633b3d0SIshai Rabinovitz 1532ee959b00STony Jones static ssize_t show_zero_req_lim(struct device *dev, 1533ee959b00STony Jones struct device_attribute *attr, char *buf) 15346bfa24faSRoland Dreier { 1535ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 15366bfa24faSRoland Dreier 15376bfa24faSRoland Dreier if (target->state == SRP_TARGET_DEAD || 15386bfa24faSRoland Dreier target->state == SRP_TARGET_REMOVED) 15396bfa24faSRoland Dreier return -ENODEV; 15406bfa24faSRoland Dreier 15416bfa24faSRoland Dreier return sprintf(buf, "%d\n", target->zero_req_lim); 15426bfa24faSRoland Dreier } 15436bfa24faSRoland Dreier 1544ee959b00STony Jones static ssize_t show_local_ib_port(struct device *dev, 1545ee959b00STony Jones struct device_attribute *attr, char *buf) 1546ded7f1a1SIshai Rabinovitz { 1547ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 1548ded7f1a1SIshai Rabinovitz 1549ded7f1a1SIshai Rabinovitz return sprintf(buf, "%d\n", target->srp_host->port); 1550ded7f1a1SIshai Rabinovitz } 1551ded7f1a1SIshai Rabinovitz 1552ee959b00STony Jones static ssize_t show_local_ib_device(struct device *dev, 1553ee959b00STony Jones struct device_attribute *attr, char *buf) 1554ded7f1a1SIshai Rabinovitz { 1555ee959b00STony Jones struct srp_target_port *target = host_to_target(class_to_shost(dev)); 1556ded7f1a1SIshai Rabinovitz 155705321937SGreg Kroah-Hartman return sprintf(buf, "%s\n", target->srp_host->srp_dev->dev->name); 1558ded7f1a1SIshai Rabinovitz } 1559ded7f1a1SIshai Rabinovitz 1560ee959b00STony Jones static DEVICE_ATTR(id_ext, S_IRUGO, show_id_ext, NULL); 1561ee959b00STony Jones static DEVICE_ATTR(ioc_guid, S_IRUGO, show_ioc_guid, NULL); 1562ee959b00STony Jones static DEVICE_ATTR(service_id, S_IRUGO, show_service_id, NULL); 1563ee959b00STony Jones static DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL); 1564ee959b00STony Jones static DEVICE_ATTR(dgid, S_IRUGO, show_dgid, NULL); 1565ee959b00STony Jones static DEVICE_ATTR(orig_dgid, S_IRUGO, show_orig_dgid, NULL); 1566ee959b00STony Jones static DEVICE_ATTR(zero_req_lim, S_IRUGO, show_zero_req_lim, NULL); 1567ee959b00STony Jones static DEVICE_ATTR(local_ib_port, S_IRUGO, show_local_ib_port, NULL); 1568ee959b00STony Jones static DEVICE_ATTR(local_ib_device, S_IRUGO, show_local_ib_device, NULL); 15696ecb0c84SRoland Dreier 1570ee959b00STony Jones static struct device_attribute *srp_host_attrs[] = { 1571ee959b00STony Jones &dev_attr_id_ext, 1572ee959b00STony Jones &dev_attr_ioc_guid, 1573ee959b00STony Jones &dev_attr_service_id, 1574ee959b00STony Jones &dev_attr_pkey, 1575ee959b00STony Jones &dev_attr_dgid, 1576ee959b00STony Jones &dev_attr_orig_dgid, 1577ee959b00STony Jones &dev_attr_zero_req_lim, 1578ee959b00STony Jones &dev_attr_local_ib_port, 1579ee959b00STony Jones &dev_attr_local_ib_device, 15806ecb0c84SRoland Dreier NULL 15816ecb0c84SRoland Dreier }; 15826ecb0c84SRoland Dreier 1583aef9ec39SRoland Dreier static struct scsi_host_template srp_template = { 1584aef9ec39SRoland Dreier .module = THIS_MODULE, 1585b7f008fdSRoland Dreier .name = "InfiniBand SRP initiator", 1586b7f008fdSRoland Dreier .proc_name = DRV_NAME, 1587aef9ec39SRoland Dreier .info = srp_target_info, 1588aef9ec39SRoland Dreier .queuecommand = srp_queuecommand, 1589aef9ec39SRoland Dreier .eh_abort_handler = srp_abort, 1590aef9ec39SRoland Dreier .eh_device_reset_handler = srp_reset_device, 1591aef9ec39SRoland Dreier .eh_host_reset_handler = srp_reset_host, 1592aef9ec39SRoland Dreier .can_queue = SRP_SQ_SIZE, 1593aef9ec39SRoland Dreier .this_id = -1, 1594aef9ec39SRoland Dreier .cmd_per_lun = SRP_SQ_SIZE, 15956ecb0c84SRoland Dreier .use_clustering = ENABLE_CLUSTERING, 15966ecb0c84SRoland Dreier .shost_attrs = srp_host_attrs 1597aef9ec39SRoland Dreier }; 1598aef9ec39SRoland Dreier 1599aef9ec39SRoland Dreier static int srp_add_target(struct srp_host *host, struct srp_target_port *target) 1600aef9ec39SRoland Dreier { 16013236822bSFUJITA Tomonori struct srp_rport_identifiers ids; 16023236822bSFUJITA Tomonori struct srp_rport *rport; 16033236822bSFUJITA Tomonori 1604aef9ec39SRoland Dreier sprintf(target->target_name, "SRP.T10:%016llX", 1605aef9ec39SRoland Dreier (unsigned long long) be64_to_cpu(target->id_ext)); 1606aef9ec39SRoland Dreier 160705321937SGreg Kroah-Hartman if (scsi_add_host(target->scsi_host, host->srp_dev->dev->dma_device)) 1608aef9ec39SRoland Dreier return -ENODEV; 1609aef9ec39SRoland Dreier 16103236822bSFUJITA Tomonori memcpy(ids.port_id, &target->id_ext, 8); 16113236822bSFUJITA Tomonori memcpy(ids.port_id + 8, &target->ioc_guid, 8); 1612aebd5e47SFUJITA Tomonori ids.roles = SRP_RPORT_ROLE_TARGET; 16133236822bSFUJITA Tomonori rport = srp_rport_add(target->scsi_host, &ids); 16143236822bSFUJITA Tomonori if (IS_ERR(rport)) { 16153236822bSFUJITA Tomonori scsi_remove_host(target->scsi_host); 16163236822bSFUJITA Tomonori return PTR_ERR(rport); 16173236822bSFUJITA Tomonori } 16183236822bSFUJITA Tomonori 1619b3589fd4SMatthew Wilcox spin_lock(&host->target_lock); 1620aef9ec39SRoland Dreier list_add_tail(&target->list, &host->target_list); 1621b3589fd4SMatthew Wilcox spin_unlock(&host->target_lock); 1622aef9ec39SRoland Dreier 1623aef9ec39SRoland Dreier target->state = SRP_TARGET_LIVE; 1624aef9ec39SRoland Dreier 1625aef9ec39SRoland Dreier scsi_scan_target(&target->scsi_host->shost_gendev, 16261962a4a1SMatthew Wilcox 0, target->scsi_id, SCAN_WILD_CARD, 0); 1627aef9ec39SRoland Dreier 1628aef9ec39SRoland Dreier return 0; 1629aef9ec39SRoland Dreier } 1630aef9ec39SRoland Dreier 1631ee959b00STony Jones static void srp_release_dev(struct device *dev) 1632aef9ec39SRoland Dreier { 1633aef9ec39SRoland Dreier struct srp_host *host = 1634ee959b00STony Jones container_of(dev, struct srp_host, dev); 1635aef9ec39SRoland Dreier 1636aef9ec39SRoland Dreier complete(&host->released); 1637aef9ec39SRoland Dreier } 1638aef9ec39SRoland Dreier 1639aef9ec39SRoland Dreier static struct class srp_class = { 1640aef9ec39SRoland Dreier .name = "infiniband_srp", 1641ee959b00STony Jones .dev_release = srp_release_dev 1642aef9ec39SRoland Dreier }; 1643aef9ec39SRoland Dreier 1644aef9ec39SRoland Dreier /* 1645aef9ec39SRoland Dreier * Target ports are added by writing 1646aef9ec39SRoland Dreier * 1647aef9ec39SRoland Dreier * id_ext=<SRP ID ext>,ioc_guid=<SRP IOC GUID>,dgid=<dest GID>, 1648aef9ec39SRoland Dreier * pkey=<P_Key>,service_id=<service ID> 1649aef9ec39SRoland Dreier * 1650aef9ec39SRoland Dreier * to the add_target sysfs attribute. 1651aef9ec39SRoland Dreier */ 1652aef9ec39SRoland Dreier enum { 1653aef9ec39SRoland Dreier SRP_OPT_ERR = 0, 1654aef9ec39SRoland Dreier SRP_OPT_ID_EXT = 1 << 0, 1655aef9ec39SRoland Dreier SRP_OPT_IOC_GUID = 1 << 1, 1656aef9ec39SRoland Dreier SRP_OPT_DGID = 1 << 2, 1657aef9ec39SRoland Dreier SRP_OPT_PKEY = 1 << 3, 1658aef9ec39SRoland Dreier SRP_OPT_SERVICE_ID = 1 << 4, 1659aef9ec39SRoland Dreier SRP_OPT_MAX_SECT = 1 << 5, 166052fb2b50SVu Pham SRP_OPT_MAX_CMD_PER_LUN = 1 << 6, 16610c0450dbSRamachandra K SRP_OPT_IO_CLASS = 1 << 7, 166201cb9bcbSIshai Rabinovitz SRP_OPT_INITIATOR_EXT = 1 << 8, 1663aef9ec39SRoland Dreier SRP_OPT_ALL = (SRP_OPT_ID_EXT | 1664aef9ec39SRoland Dreier SRP_OPT_IOC_GUID | 1665aef9ec39SRoland Dreier SRP_OPT_DGID | 1666aef9ec39SRoland Dreier SRP_OPT_PKEY | 1667aef9ec39SRoland Dreier SRP_OPT_SERVICE_ID), 1668aef9ec39SRoland Dreier }; 1669aef9ec39SRoland Dreier 1670a447c093SSteven Whitehouse static const match_table_t srp_opt_tokens = { 1671aef9ec39SRoland Dreier { SRP_OPT_ID_EXT, "id_ext=%s" }, 1672aef9ec39SRoland Dreier { SRP_OPT_IOC_GUID, "ioc_guid=%s" }, 1673aef9ec39SRoland Dreier { SRP_OPT_DGID, "dgid=%s" }, 1674aef9ec39SRoland Dreier { SRP_OPT_PKEY, "pkey=%x" }, 1675aef9ec39SRoland Dreier { SRP_OPT_SERVICE_ID, "service_id=%s" }, 1676aef9ec39SRoland Dreier { SRP_OPT_MAX_SECT, "max_sect=%d" }, 167752fb2b50SVu Pham { SRP_OPT_MAX_CMD_PER_LUN, "max_cmd_per_lun=%d" }, 16780c0450dbSRamachandra K { SRP_OPT_IO_CLASS, "io_class=%x" }, 167901cb9bcbSIshai Rabinovitz { SRP_OPT_INITIATOR_EXT, "initiator_ext=%s" }, 1680aef9ec39SRoland Dreier { SRP_OPT_ERR, NULL } 1681aef9ec39SRoland Dreier }; 1682aef9ec39SRoland Dreier 1683aef9ec39SRoland Dreier static int srp_parse_options(const char *buf, struct srp_target_port *target) 1684aef9ec39SRoland Dreier { 1685aef9ec39SRoland Dreier char *options, *sep_opt; 1686aef9ec39SRoland Dreier char *p; 1687aef9ec39SRoland Dreier char dgid[3]; 1688aef9ec39SRoland Dreier substring_t args[MAX_OPT_ARGS]; 1689aef9ec39SRoland Dreier int opt_mask = 0; 1690aef9ec39SRoland Dreier int token; 1691aef9ec39SRoland Dreier int ret = -EINVAL; 1692aef9ec39SRoland Dreier int i; 1693aef9ec39SRoland Dreier 1694aef9ec39SRoland Dreier options = kstrdup(buf, GFP_KERNEL); 1695aef9ec39SRoland Dreier if (!options) 1696aef9ec39SRoland Dreier return -ENOMEM; 1697aef9ec39SRoland Dreier 1698aef9ec39SRoland Dreier sep_opt = options; 1699aef9ec39SRoland Dreier while ((p = strsep(&sep_opt, ",")) != NULL) { 1700aef9ec39SRoland Dreier if (!*p) 1701aef9ec39SRoland Dreier continue; 1702aef9ec39SRoland Dreier 1703aef9ec39SRoland Dreier token = match_token(p, srp_opt_tokens, args); 1704aef9ec39SRoland Dreier opt_mask |= token; 1705aef9ec39SRoland Dreier 1706aef9ec39SRoland Dreier switch (token) { 1707aef9ec39SRoland Dreier case SRP_OPT_ID_EXT: 1708aef9ec39SRoland Dreier p = match_strdup(args); 1709a20f3a6dSIshai Rabinovitz if (!p) { 1710a20f3a6dSIshai Rabinovitz ret = -ENOMEM; 1711a20f3a6dSIshai Rabinovitz goto out; 1712a20f3a6dSIshai Rabinovitz } 1713aef9ec39SRoland Dreier target->id_ext = cpu_to_be64(simple_strtoull(p, NULL, 16)); 1714aef9ec39SRoland Dreier kfree(p); 1715aef9ec39SRoland Dreier break; 1716aef9ec39SRoland Dreier 1717aef9ec39SRoland Dreier case SRP_OPT_IOC_GUID: 1718aef9ec39SRoland Dreier p = match_strdup(args); 1719a20f3a6dSIshai Rabinovitz if (!p) { 1720a20f3a6dSIshai Rabinovitz ret = -ENOMEM; 1721a20f3a6dSIshai Rabinovitz goto out; 1722a20f3a6dSIshai Rabinovitz } 1723aef9ec39SRoland Dreier target->ioc_guid = cpu_to_be64(simple_strtoull(p, NULL, 16)); 1724aef9ec39SRoland Dreier kfree(p); 1725aef9ec39SRoland Dreier break; 1726aef9ec39SRoland Dreier 1727aef9ec39SRoland Dreier case SRP_OPT_DGID: 1728aef9ec39SRoland Dreier p = match_strdup(args); 1729a20f3a6dSIshai Rabinovitz if (!p) { 1730a20f3a6dSIshai Rabinovitz ret = -ENOMEM; 1731a20f3a6dSIshai Rabinovitz goto out; 1732a20f3a6dSIshai Rabinovitz } 1733aef9ec39SRoland Dreier if (strlen(p) != 32) { 1734aef9ec39SRoland Dreier printk(KERN_WARNING PFX "bad dest GID parameter '%s'\n", p); 1735ce1823f0SRoland Dreier kfree(p); 1736aef9ec39SRoland Dreier goto out; 1737aef9ec39SRoland Dreier } 1738aef9ec39SRoland Dreier 1739aef9ec39SRoland Dreier for (i = 0; i < 16; ++i) { 1740aef9ec39SRoland Dreier strlcpy(dgid, p + i * 2, 3); 1741aef9ec39SRoland Dreier target->path.dgid.raw[i] = simple_strtoul(dgid, NULL, 16); 1742aef9ec39SRoland Dreier } 1743bf17c1c7SRoland Dreier kfree(p); 17443633b3d0SIshai Rabinovitz memcpy(target->orig_dgid, target->path.dgid.raw, 16); 1745aef9ec39SRoland Dreier break; 1746aef9ec39SRoland Dreier 1747aef9ec39SRoland Dreier case SRP_OPT_PKEY: 1748aef9ec39SRoland Dreier if (match_hex(args, &token)) { 1749aef9ec39SRoland Dreier printk(KERN_WARNING PFX "bad P_Key parameter '%s'\n", p); 1750aef9ec39SRoland Dreier goto out; 1751aef9ec39SRoland Dreier } 1752aef9ec39SRoland Dreier target->path.pkey = cpu_to_be16(token); 1753aef9ec39SRoland Dreier break; 1754aef9ec39SRoland Dreier 1755aef9ec39SRoland Dreier case SRP_OPT_SERVICE_ID: 1756aef9ec39SRoland Dreier p = match_strdup(args); 1757a20f3a6dSIshai Rabinovitz if (!p) { 1758a20f3a6dSIshai Rabinovitz ret = -ENOMEM; 1759a20f3a6dSIshai Rabinovitz goto out; 1760a20f3a6dSIshai Rabinovitz } 1761aef9ec39SRoland Dreier target->service_id = cpu_to_be64(simple_strtoull(p, NULL, 16)); 1762247e020eSSean Hefty target->path.service_id = target->service_id; 1763aef9ec39SRoland Dreier kfree(p); 1764aef9ec39SRoland Dreier break; 1765aef9ec39SRoland Dreier 1766aef9ec39SRoland Dreier case SRP_OPT_MAX_SECT: 1767aef9ec39SRoland Dreier if (match_int(args, &token)) { 1768aef9ec39SRoland Dreier printk(KERN_WARNING PFX "bad max sect parameter '%s'\n", p); 1769aef9ec39SRoland Dreier goto out; 1770aef9ec39SRoland Dreier } 1771aef9ec39SRoland Dreier target->scsi_host->max_sectors = token; 1772aef9ec39SRoland Dreier break; 1773aef9ec39SRoland Dreier 177452fb2b50SVu Pham case SRP_OPT_MAX_CMD_PER_LUN: 177552fb2b50SVu Pham if (match_int(args, &token)) { 177652fb2b50SVu Pham printk(KERN_WARNING PFX "bad max cmd_per_lun parameter '%s'\n", p); 177752fb2b50SVu Pham goto out; 177852fb2b50SVu Pham } 177952fb2b50SVu Pham target->scsi_host->cmd_per_lun = min(token, SRP_SQ_SIZE); 178052fb2b50SVu Pham break; 178152fb2b50SVu Pham 17820c0450dbSRamachandra K case SRP_OPT_IO_CLASS: 17830c0450dbSRamachandra K if (match_hex(args, &token)) { 17840c0450dbSRamachandra K printk(KERN_WARNING PFX "bad IO class parameter '%s' \n", p); 17850c0450dbSRamachandra K goto out; 17860c0450dbSRamachandra K } 17870c0450dbSRamachandra K if (token != SRP_REV10_IB_IO_CLASS && 17880c0450dbSRamachandra K token != SRP_REV16A_IB_IO_CLASS) { 17890c0450dbSRamachandra K printk(KERN_WARNING PFX "unknown IO class parameter value" 17900c0450dbSRamachandra K " %x specified (use %x or %x).\n", 17910c0450dbSRamachandra K token, SRP_REV10_IB_IO_CLASS, SRP_REV16A_IB_IO_CLASS); 17920c0450dbSRamachandra K goto out; 17930c0450dbSRamachandra K } 17940c0450dbSRamachandra K target->io_class = token; 17950c0450dbSRamachandra K break; 17960c0450dbSRamachandra K 179701cb9bcbSIshai Rabinovitz case SRP_OPT_INITIATOR_EXT: 179801cb9bcbSIshai Rabinovitz p = match_strdup(args); 1799a20f3a6dSIshai Rabinovitz if (!p) { 1800a20f3a6dSIshai Rabinovitz ret = -ENOMEM; 1801a20f3a6dSIshai Rabinovitz goto out; 1802a20f3a6dSIshai Rabinovitz } 180301cb9bcbSIshai Rabinovitz target->initiator_ext = cpu_to_be64(simple_strtoull(p, NULL, 16)); 180401cb9bcbSIshai Rabinovitz kfree(p); 180501cb9bcbSIshai Rabinovitz break; 180601cb9bcbSIshai Rabinovitz 1807aef9ec39SRoland Dreier default: 1808aef9ec39SRoland Dreier printk(KERN_WARNING PFX "unknown parameter or missing value " 1809aef9ec39SRoland Dreier "'%s' in target creation request\n", p); 1810aef9ec39SRoland Dreier goto out; 1811aef9ec39SRoland Dreier } 1812aef9ec39SRoland Dreier } 1813aef9ec39SRoland Dreier 1814aef9ec39SRoland Dreier if ((opt_mask & SRP_OPT_ALL) == SRP_OPT_ALL) 1815aef9ec39SRoland Dreier ret = 0; 1816aef9ec39SRoland Dreier else 1817aef9ec39SRoland Dreier for (i = 0; i < ARRAY_SIZE(srp_opt_tokens); ++i) 1818aef9ec39SRoland Dreier if ((srp_opt_tokens[i].token & SRP_OPT_ALL) && 1819aef9ec39SRoland Dreier !(srp_opt_tokens[i].token & opt_mask)) 1820aef9ec39SRoland Dreier printk(KERN_WARNING PFX "target creation request is " 1821aef9ec39SRoland Dreier "missing parameter '%s'\n", 1822aef9ec39SRoland Dreier srp_opt_tokens[i].pattern); 1823aef9ec39SRoland Dreier 1824aef9ec39SRoland Dreier out: 1825aef9ec39SRoland Dreier kfree(options); 1826aef9ec39SRoland Dreier return ret; 1827aef9ec39SRoland Dreier } 1828aef9ec39SRoland Dreier 1829ee959b00STony Jones static ssize_t srp_create_target(struct device *dev, 1830ee959b00STony Jones struct device_attribute *attr, 1831aef9ec39SRoland Dreier const char *buf, size_t count) 1832aef9ec39SRoland Dreier { 1833aef9ec39SRoland Dreier struct srp_host *host = 1834ee959b00STony Jones container_of(dev, struct srp_host, dev); 1835aef9ec39SRoland Dreier struct Scsi_Host *target_host; 1836aef9ec39SRoland Dreier struct srp_target_port *target; 1837aef9ec39SRoland Dreier int ret; 1838aef9ec39SRoland Dreier int i; 1839aef9ec39SRoland Dreier 1840aef9ec39SRoland Dreier target_host = scsi_host_alloc(&srp_template, 1841aef9ec39SRoland Dreier sizeof (struct srp_target_port)); 1842aef9ec39SRoland Dreier if (!target_host) 1843aef9ec39SRoland Dreier return -ENOMEM; 1844aef9ec39SRoland Dreier 18453236822bSFUJITA Tomonori target_host->transportt = ib_srp_transport_template; 18465f068992SRoland Dreier target_host->max_lun = SRP_MAX_LUN; 18473c8edf0eSArne Redlich target_host->max_cmd_len = sizeof ((struct srp_cmd *) (void *) 0L)->cdb; 18485f068992SRoland Dreier 1849aef9ec39SRoland Dreier target = host_to_target(target_host); 1850aef9ec39SRoland Dreier 18510c0450dbSRamachandra K target->io_class = SRP_REV16A_IB_IO_CLASS; 1852aef9ec39SRoland Dreier target->scsi_host = target_host; 1853aef9ec39SRoland Dreier target->srp_host = host; 1854aef9ec39SRoland Dreier 1855d945e1dfSRoland Dreier INIT_LIST_HEAD(&target->free_reqs); 1856aef9ec39SRoland Dreier INIT_LIST_HEAD(&target->req_queue); 1857d945e1dfSRoland Dreier for (i = 0; i < SRP_SQ_SIZE; ++i) { 1858d945e1dfSRoland Dreier target->req_ring[i].index = i; 1859d945e1dfSRoland Dreier list_add_tail(&target->req_ring[i].list, &target->free_reqs); 1860d945e1dfSRoland Dreier } 1861aef9ec39SRoland Dreier 1862aef9ec39SRoland Dreier ret = srp_parse_options(buf, target); 1863aef9ec39SRoland Dreier if (ret) 1864aef9ec39SRoland Dreier goto err; 1865aef9ec39SRoland Dreier 1866969a60f9SRoland Dreier ib_query_gid(host->srp_dev->dev, host->port, 0, &target->path.sgid); 1867aef9ec39SRoland Dreier 18687aa54bd7SDavid Dillow shost_printk(KERN_DEBUG, target->scsi_host, PFX 18697aa54bd7SDavid Dillow "new target: id_ext %016llx ioc_guid %016llx pkey %04x " 1870*8867cd7cSHarvey Harrison "service_id %016llx dgid %p6\n", 1871aef9ec39SRoland Dreier (unsigned long long) be64_to_cpu(target->id_ext), 1872aef9ec39SRoland Dreier (unsigned long long) be64_to_cpu(target->ioc_guid), 1873aef9ec39SRoland Dreier be16_to_cpu(target->path.pkey), 1874aef9ec39SRoland Dreier (unsigned long long) be64_to_cpu(target->service_id), 1875*8867cd7cSHarvey Harrison target->path.dgid.raw); 1876aef9ec39SRoland Dreier 1877aef9ec39SRoland Dreier ret = srp_create_target_ib(target); 1878aef9ec39SRoland Dreier if (ret) 1879aef9ec39SRoland Dreier goto err; 1880aef9ec39SRoland Dreier 18819fe4bcf4SDavid Dillow ret = srp_new_cm_id(target); 18829fe4bcf4SDavid Dillow if (ret) 1883aef9ec39SRoland Dreier goto err_free; 1884aef9ec39SRoland Dreier 18851033ff67SIshai Rabinovitz target->qp_in_error = 0; 1886aef9ec39SRoland Dreier ret = srp_connect_target(target); 1887aef9ec39SRoland Dreier if (ret) { 18887aa54bd7SDavid Dillow shost_printk(KERN_ERR, target->scsi_host, 18897aa54bd7SDavid Dillow PFX "Connection failed\n"); 1890aef9ec39SRoland Dreier goto err_cm_id; 1891aef9ec39SRoland Dreier } 1892aef9ec39SRoland Dreier 1893aef9ec39SRoland Dreier ret = srp_add_target(host, target); 1894aef9ec39SRoland Dreier if (ret) 1895aef9ec39SRoland Dreier goto err_disconnect; 1896aef9ec39SRoland Dreier 1897aef9ec39SRoland Dreier return count; 1898aef9ec39SRoland Dreier 1899aef9ec39SRoland Dreier err_disconnect: 1900aef9ec39SRoland Dreier srp_disconnect_target(target); 1901aef9ec39SRoland Dreier 1902aef9ec39SRoland Dreier err_cm_id: 1903aef9ec39SRoland Dreier ib_destroy_cm_id(target->cm_id); 1904aef9ec39SRoland Dreier 1905aef9ec39SRoland Dreier err_free: 1906aef9ec39SRoland Dreier srp_free_target_ib(target); 1907aef9ec39SRoland Dreier 1908aef9ec39SRoland Dreier err: 1909aef9ec39SRoland Dreier scsi_host_put(target_host); 1910aef9ec39SRoland Dreier 1911aef9ec39SRoland Dreier return ret; 1912aef9ec39SRoland Dreier } 1913aef9ec39SRoland Dreier 1914ee959b00STony Jones static DEVICE_ATTR(add_target, S_IWUSR, NULL, srp_create_target); 1915aef9ec39SRoland Dreier 1916ee959b00STony Jones static ssize_t show_ibdev(struct device *dev, struct device_attribute *attr, 1917ee959b00STony Jones char *buf) 1918aef9ec39SRoland Dreier { 1919ee959b00STony Jones struct srp_host *host = container_of(dev, struct srp_host, dev); 1920aef9ec39SRoland Dreier 192105321937SGreg Kroah-Hartman return sprintf(buf, "%s\n", host->srp_dev->dev->name); 1922aef9ec39SRoland Dreier } 1923aef9ec39SRoland Dreier 1924ee959b00STony Jones static DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL); 1925aef9ec39SRoland Dreier 1926ee959b00STony Jones static ssize_t show_port(struct device *dev, struct device_attribute *attr, 1927ee959b00STony Jones char *buf) 1928aef9ec39SRoland Dreier { 1929ee959b00STony Jones struct srp_host *host = container_of(dev, struct srp_host, dev); 1930aef9ec39SRoland Dreier 1931aef9ec39SRoland Dreier return sprintf(buf, "%d\n", host->port); 1932aef9ec39SRoland Dreier } 1933aef9ec39SRoland Dreier 1934ee959b00STony Jones static DEVICE_ATTR(port, S_IRUGO, show_port, NULL); 1935aef9ec39SRoland Dreier 1936f5358a17SRoland Dreier static struct srp_host *srp_add_port(struct srp_device *device, u8 port) 1937aef9ec39SRoland Dreier { 1938aef9ec39SRoland Dreier struct srp_host *host; 1939aef9ec39SRoland Dreier 1940aef9ec39SRoland Dreier host = kzalloc(sizeof *host, GFP_KERNEL); 1941aef9ec39SRoland Dreier if (!host) 1942aef9ec39SRoland Dreier return NULL; 1943aef9ec39SRoland Dreier 1944aef9ec39SRoland Dreier INIT_LIST_HEAD(&host->target_list); 1945b3589fd4SMatthew Wilcox spin_lock_init(&host->target_lock); 1946aef9ec39SRoland Dreier init_completion(&host->released); 194705321937SGreg Kroah-Hartman host->srp_dev = device; 1948aef9ec39SRoland Dreier host->port = port; 1949aef9ec39SRoland Dreier 1950ee959b00STony Jones host->dev.class = &srp_class; 1951ee959b00STony Jones host->dev.parent = device->dev->dma_device; 1952ee959b00STony Jones snprintf(host->dev.bus_id, BUS_ID_SIZE, "srp-%s-%d", 1953f5358a17SRoland Dreier device->dev->name, port); 1954aef9ec39SRoland Dreier 1955ee959b00STony Jones if (device_register(&host->dev)) 1956f5358a17SRoland Dreier goto free_host; 1957ee959b00STony Jones if (device_create_file(&host->dev, &dev_attr_add_target)) 1958aef9ec39SRoland Dreier goto err_class; 1959ee959b00STony Jones if (device_create_file(&host->dev, &dev_attr_ibdev)) 1960aef9ec39SRoland Dreier goto err_class; 1961ee959b00STony Jones if (device_create_file(&host->dev, &dev_attr_port)) 1962aef9ec39SRoland Dreier goto err_class; 1963aef9ec39SRoland Dreier 1964aef9ec39SRoland Dreier return host; 1965aef9ec39SRoland Dreier 1966aef9ec39SRoland Dreier err_class: 1967ee959b00STony Jones device_unregister(&host->dev); 1968aef9ec39SRoland Dreier 1969f5358a17SRoland Dreier free_host: 1970aef9ec39SRoland Dreier kfree(host); 1971aef9ec39SRoland Dreier 1972aef9ec39SRoland Dreier return NULL; 1973aef9ec39SRoland Dreier } 1974aef9ec39SRoland Dreier 1975aef9ec39SRoland Dreier static void srp_add_one(struct ib_device *device) 1976aef9ec39SRoland Dreier { 1977f5358a17SRoland Dreier struct srp_device *srp_dev; 1978f5358a17SRoland Dreier struct ib_device_attr *dev_attr; 1979f5358a17SRoland Dreier struct ib_fmr_pool_param fmr_param; 1980aef9ec39SRoland Dreier struct srp_host *host; 1981aef9ec39SRoland Dreier int s, e, p; 1982aef9ec39SRoland Dreier 1983f5358a17SRoland Dreier dev_attr = kmalloc(sizeof *dev_attr, GFP_KERNEL); 1984f5358a17SRoland Dreier if (!dev_attr) 1985cf311cd4SSean Hefty return; 1986aef9ec39SRoland Dreier 1987f5358a17SRoland Dreier if (ib_query_device(device, dev_attr)) { 1988f5358a17SRoland Dreier printk(KERN_WARNING PFX "Query device failed for %s\n", 1989f5358a17SRoland Dreier device->name); 1990f5358a17SRoland Dreier goto free_attr; 1991f5358a17SRoland Dreier } 1992f5358a17SRoland Dreier 1993f5358a17SRoland Dreier srp_dev = kmalloc(sizeof *srp_dev, GFP_KERNEL); 1994f5358a17SRoland Dreier if (!srp_dev) 1995f5358a17SRoland Dreier goto free_attr; 1996f5358a17SRoland Dreier 1997f5358a17SRoland Dreier /* 1998f5358a17SRoland Dreier * Use the smallest page size supported by the HCA, down to a 1999f5358a17SRoland Dreier * minimum of 512 bytes (which is the smallest sector that a 2000f5358a17SRoland Dreier * SCSI command will ever carry). 2001f5358a17SRoland Dreier */ 2002f5358a17SRoland Dreier srp_dev->fmr_page_shift = max(9, ffs(dev_attr->page_size_cap) - 1); 2003f5358a17SRoland Dreier srp_dev->fmr_page_size = 1 << srp_dev->fmr_page_shift; 2004bf628dc2SRoland Dreier srp_dev->fmr_page_mask = ~((u64) srp_dev->fmr_page_size - 1); 2005f5358a17SRoland Dreier 2006f5358a17SRoland Dreier INIT_LIST_HEAD(&srp_dev->dev_list); 2007f5358a17SRoland Dreier 2008f5358a17SRoland Dreier srp_dev->dev = device; 2009f5358a17SRoland Dreier srp_dev->pd = ib_alloc_pd(device); 2010f5358a17SRoland Dreier if (IS_ERR(srp_dev->pd)) 2011f5358a17SRoland Dreier goto free_dev; 2012f5358a17SRoland Dreier 2013f5358a17SRoland Dreier srp_dev->mr = ib_get_dma_mr(srp_dev->pd, 2014f5358a17SRoland Dreier IB_ACCESS_LOCAL_WRITE | 2015f5358a17SRoland Dreier IB_ACCESS_REMOTE_READ | 2016f5358a17SRoland Dreier IB_ACCESS_REMOTE_WRITE); 2017f5358a17SRoland Dreier if (IS_ERR(srp_dev->mr)) 2018f5358a17SRoland Dreier goto err_pd; 2019f5358a17SRoland Dreier 2020f5358a17SRoland Dreier memset(&fmr_param, 0, sizeof fmr_param); 2021f5358a17SRoland Dreier fmr_param.pool_size = SRP_FMR_POOL_SIZE; 2022f5358a17SRoland Dreier fmr_param.dirty_watermark = SRP_FMR_DIRTY_SIZE; 2023f5358a17SRoland Dreier fmr_param.cache = 1; 2024f5358a17SRoland Dreier fmr_param.max_pages_per_fmr = SRP_FMR_SIZE; 2025f5358a17SRoland Dreier fmr_param.page_shift = srp_dev->fmr_page_shift; 2026f5358a17SRoland Dreier fmr_param.access = (IB_ACCESS_LOCAL_WRITE | 2027f5358a17SRoland Dreier IB_ACCESS_REMOTE_WRITE | 2028f5358a17SRoland Dreier IB_ACCESS_REMOTE_READ); 2029f5358a17SRoland Dreier 2030f5358a17SRoland Dreier srp_dev->fmr_pool = ib_create_fmr_pool(srp_dev->pd, &fmr_param); 2031f5358a17SRoland Dreier if (IS_ERR(srp_dev->fmr_pool)) 2032f5358a17SRoland Dreier srp_dev->fmr_pool = NULL; 2033aef9ec39SRoland Dreier 203407ebafbaSTom Tucker if (device->node_type == RDMA_NODE_IB_SWITCH) { 2035aef9ec39SRoland Dreier s = 0; 2036aef9ec39SRoland Dreier e = 0; 2037aef9ec39SRoland Dreier } else { 2038aef9ec39SRoland Dreier s = 1; 2039aef9ec39SRoland Dreier e = device->phys_port_cnt; 2040aef9ec39SRoland Dreier } 2041aef9ec39SRoland Dreier 2042aef9ec39SRoland Dreier for (p = s; p <= e; ++p) { 2043f5358a17SRoland Dreier host = srp_add_port(srp_dev, p); 2044aef9ec39SRoland Dreier if (host) 2045f5358a17SRoland Dreier list_add_tail(&host->list, &srp_dev->dev_list); 2046aef9ec39SRoland Dreier } 2047aef9ec39SRoland Dreier 2048f5358a17SRoland Dreier ib_set_client_data(device, &srp_client, srp_dev); 2049f5358a17SRoland Dreier 2050f5358a17SRoland Dreier goto free_attr; 2051f5358a17SRoland Dreier 2052f5358a17SRoland Dreier err_pd: 2053f5358a17SRoland Dreier ib_dealloc_pd(srp_dev->pd); 2054f5358a17SRoland Dreier 2055f5358a17SRoland Dreier free_dev: 2056f5358a17SRoland Dreier kfree(srp_dev); 2057f5358a17SRoland Dreier 2058f5358a17SRoland Dreier free_attr: 2059f5358a17SRoland Dreier kfree(dev_attr); 2060aef9ec39SRoland Dreier } 2061aef9ec39SRoland Dreier 2062aef9ec39SRoland Dreier static void srp_remove_one(struct ib_device *device) 2063aef9ec39SRoland Dreier { 2064f5358a17SRoland Dreier struct srp_device *srp_dev; 2065aef9ec39SRoland Dreier struct srp_host *host, *tmp_host; 2066aef9ec39SRoland Dreier LIST_HEAD(target_list); 2067aef9ec39SRoland Dreier struct srp_target_port *target, *tmp_target; 2068aef9ec39SRoland Dreier 2069f5358a17SRoland Dreier srp_dev = ib_get_client_data(device, &srp_client); 2070aef9ec39SRoland Dreier 2071f5358a17SRoland Dreier list_for_each_entry_safe(host, tmp_host, &srp_dev->dev_list, list) { 2072ee959b00STony Jones device_unregister(&host->dev); 2073aef9ec39SRoland Dreier /* 2074aef9ec39SRoland Dreier * Wait for the sysfs entry to go away, so that no new 2075aef9ec39SRoland Dreier * target ports can be created. 2076aef9ec39SRoland Dreier */ 2077aef9ec39SRoland Dreier wait_for_completion(&host->released); 2078aef9ec39SRoland Dreier 2079aef9ec39SRoland Dreier /* 2080aef9ec39SRoland Dreier * Mark all target ports as removed, so we stop queueing 2081aef9ec39SRoland Dreier * commands and don't try to reconnect. 2082aef9ec39SRoland Dreier */ 2083b3589fd4SMatthew Wilcox spin_lock(&host->target_lock); 2084549c5fc2SMatthew Wilcox list_for_each_entry(target, &host->target_list, list) { 20850c5b3952SIshai Rabinovitz spin_lock_irq(target->scsi_host->host_lock); 2086aef9ec39SRoland Dreier target->state = SRP_TARGET_REMOVED; 20870c5b3952SIshai Rabinovitz spin_unlock_irq(target->scsi_host->host_lock); 2088aef9ec39SRoland Dreier } 2089b3589fd4SMatthew Wilcox spin_unlock(&host->target_lock); 2090aef9ec39SRoland Dreier 2091aef9ec39SRoland Dreier /* 2092aef9ec39SRoland Dreier * Wait for any reconnection tasks that may have 2093aef9ec39SRoland Dreier * started before we marked our target ports as 2094aef9ec39SRoland Dreier * removed, and any target port removal tasks. 2095aef9ec39SRoland Dreier */ 2096aef9ec39SRoland Dreier flush_scheduled_work(); 2097aef9ec39SRoland Dreier 2098aef9ec39SRoland Dreier list_for_each_entry_safe(target, tmp_target, 2099aef9ec39SRoland Dreier &host->target_list, list) { 2100b0e47c8bSDavid Dillow srp_remove_host(target->scsi_host); 2101ad696989SDave Dillow scsi_remove_host(target->scsi_host); 2102aef9ec39SRoland Dreier srp_disconnect_target(target); 2103aef9ec39SRoland Dreier ib_destroy_cm_id(target->cm_id); 2104aef9ec39SRoland Dreier srp_free_target_ib(target); 2105aef9ec39SRoland Dreier scsi_host_put(target->scsi_host); 2106aef9ec39SRoland Dreier } 2107aef9ec39SRoland Dreier 2108aef9ec39SRoland Dreier kfree(host); 2109aef9ec39SRoland Dreier } 2110aef9ec39SRoland Dreier 2111f5358a17SRoland Dreier if (srp_dev->fmr_pool) 2112f5358a17SRoland Dreier ib_destroy_fmr_pool(srp_dev->fmr_pool); 2113f5358a17SRoland Dreier ib_dereg_mr(srp_dev->mr); 2114f5358a17SRoland Dreier ib_dealloc_pd(srp_dev->pd); 2115f5358a17SRoland Dreier 2116f5358a17SRoland Dreier kfree(srp_dev); 2117aef9ec39SRoland Dreier } 2118aef9ec39SRoland Dreier 21193236822bSFUJITA Tomonori static struct srp_function_template ib_srp_transport_functions = { 21203236822bSFUJITA Tomonori }; 21213236822bSFUJITA Tomonori 2122aef9ec39SRoland Dreier static int __init srp_init_module(void) 2123aef9ec39SRoland Dreier { 2124aef9ec39SRoland Dreier int ret; 2125aef9ec39SRoland Dreier 21261e89a194SDavid Dillow if (srp_sg_tablesize > 255) { 21271e89a194SDavid Dillow printk(KERN_WARNING PFX "Clamping srp_sg_tablesize to 255\n"); 21281e89a194SDavid Dillow srp_sg_tablesize = 255; 21291e89a194SDavid Dillow } 21301e89a194SDavid Dillow 21313236822bSFUJITA Tomonori ib_srp_transport_template = 21323236822bSFUJITA Tomonori srp_attach_transport(&ib_srp_transport_functions); 21333236822bSFUJITA Tomonori if (!ib_srp_transport_template) 21343236822bSFUJITA Tomonori return -ENOMEM; 21353236822bSFUJITA Tomonori 213674b0a15bSVu Pham srp_template.sg_tablesize = srp_sg_tablesize; 213774b0a15bSVu Pham srp_max_iu_len = (sizeof (struct srp_cmd) + 213874b0a15bSVu Pham sizeof (struct srp_indirect_buf) + 213974b0a15bSVu Pham srp_sg_tablesize * 16); 214074b0a15bSVu Pham 2141aef9ec39SRoland Dreier ret = class_register(&srp_class); 2142aef9ec39SRoland Dreier if (ret) { 2143aef9ec39SRoland Dreier printk(KERN_ERR PFX "couldn't register class infiniband_srp\n"); 21443236822bSFUJITA Tomonori srp_release_transport(ib_srp_transport_template); 2145aef9ec39SRoland Dreier return ret; 2146aef9ec39SRoland Dreier } 2147aef9ec39SRoland Dreier 2148c1a0b23bSMichael S. Tsirkin ib_sa_register_client(&srp_sa_client); 2149c1a0b23bSMichael S. Tsirkin 2150aef9ec39SRoland Dreier ret = ib_register_client(&srp_client); 2151aef9ec39SRoland Dreier if (ret) { 2152aef9ec39SRoland Dreier printk(KERN_ERR PFX "couldn't register IB client\n"); 21533236822bSFUJITA Tomonori srp_release_transport(ib_srp_transport_template); 2154c1a0b23bSMichael S. Tsirkin ib_sa_unregister_client(&srp_sa_client); 2155aef9ec39SRoland Dreier class_unregister(&srp_class); 2156aef9ec39SRoland Dreier return ret; 2157aef9ec39SRoland Dreier } 2158aef9ec39SRoland Dreier 2159aef9ec39SRoland Dreier return 0; 2160aef9ec39SRoland Dreier } 2161aef9ec39SRoland Dreier 2162aef9ec39SRoland Dreier static void __exit srp_cleanup_module(void) 2163aef9ec39SRoland Dreier { 2164aef9ec39SRoland Dreier ib_unregister_client(&srp_client); 2165c1a0b23bSMichael S. Tsirkin ib_sa_unregister_client(&srp_sa_client); 2166aef9ec39SRoland Dreier class_unregister(&srp_class); 21673236822bSFUJITA Tomonori srp_release_transport(ib_srp_transport_template); 2168aef9ec39SRoland Dreier } 2169aef9ec39SRoland Dreier 2170aef9ec39SRoland Dreier module_init(srp_init_module); 2171aef9ec39SRoland Dreier module_exit(srp_cleanup_module); 2172