linux/drivers/scsi/scsi_transport_srp.c
<<
>>
Prefs
   1/*
   2 * SCSI RDMA (SRP) transport class
   3 *
   4 * Copyright (C) 2007 FUJITA Tomonori <tomof@acm.org>
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License as
   8 * published by the Free Software Foundation, version 2 of the
   9 * License.
  10 *
  11 * This program is distributed in the hope that it will be useful, but
  12 * WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14 * General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU General Public License
  17 * along with this program; if not, write to the Free Software
  18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  19 * 02110-1301 USA
  20 */
  21#include <linux/init.h>
  22#include <linux/module.h>
  23#include <linux/jiffies.h>
  24#include <linux/err.h>
  25#include <linux/slab.h>
  26#include <linux/string.h>
  27
  28#include <scsi/scsi.h>
  29#include <scsi/scsi_device.h>
  30#include <scsi/scsi_host.h>
  31#include <scsi/scsi_transport.h>
  32#include <scsi/scsi_transport_srp.h>
  33#include "scsi_transport_srp_internal.h"
  34
  35struct srp_host_attrs {
  36        atomic_t next_port_id;
  37};
  38#define to_srp_host_attrs(host) ((struct srp_host_attrs *)(host)->shost_data)
  39
  40#define SRP_HOST_ATTRS 0
  41#define SRP_RPORT_ATTRS 2
  42
  43struct srp_internal {
  44        struct scsi_transport_template t;
  45        struct srp_function_template *f;
  46
  47        struct device_attribute *host_attrs[SRP_HOST_ATTRS + 1];
  48
  49        struct device_attribute *rport_attrs[SRP_RPORT_ATTRS + 1];
  50        struct device_attribute private_rport_attrs[SRP_RPORT_ATTRS];
  51        struct transport_container rport_attr_cont;
  52};
  53
  54#define to_srp_internal(tmpl) container_of(tmpl, struct srp_internal, t)
  55
  56#define dev_to_rport(d) container_of(d, struct srp_rport, dev)
  57#define transport_class_to_srp_rport(dev) dev_to_rport((dev)->parent)
  58
  59static int srp_host_setup(struct transport_container *tc, struct device *dev,
  60                          struct device *cdev)
  61{
  62        struct Scsi_Host *shost = dev_to_shost(dev);
  63        struct srp_host_attrs *srp_host = to_srp_host_attrs(shost);
  64
  65        atomic_set(&srp_host->next_port_id, 0);
  66        return 0;
  67}
  68
  69static DECLARE_TRANSPORT_CLASS(srp_host_class, "srp_host", srp_host_setup,
  70                               NULL, NULL);
  71
  72static DECLARE_TRANSPORT_CLASS(srp_rport_class, "srp_remote_ports",
  73                               NULL, NULL, NULL);
  74
  75#define SETUP_TEMPLATE(attrb, field, perm, test, ro_test, ro_perm)      \
  76        i->private_##attrb[count] = dev_attr_##field;           \
  77        i->private_##attrb[count].attr.mode = perm;                     \
  78        if (ro_test) {                                                  \
  79                i->private_##attrb[count].attr.mode = ro_perm;          \
  80                i->private_##attrb[count].store = NULL;                 \
  81        }                                                               \
  82        i->attrb[count] = &i->private_##attrb[count];                   \
  83        if (test)                                                       \
  84                count++
  85
  86#define SETUP_RPORT_ATTRIBUTE_RD(field)                                 \
  87        SETUP_TEMPLATE(rport_attrs, field, S_IRUGO, 1, 0, 0)
  88
  89#define SETUP_RPORT_ATTRIBUTE_RW(field)                                 \
  90        SETUP_TEMPLATE(rport_attrs, field, S_IRUGO | S_IWUSR,           \
  91                       1, 1, S_IRUGO)
  92
  93#define SRP_PID(p) \
  94        (p)->port_id[0], (p)->port_id[1], (p)->port_id[2], (p)->port_id[3], \
  95        (p)->port_id[4], (p)->port_id[5], (p)->port_id[6], (p)->port_id[7], \
  96        (p)->port_id[8], (p)->port_id[9], (p)->port_id[10], (p)->port_id[11], \
  97        (p)->port_id[12], (p)->port_id[13], (p)->port_id[14], (p)->port_id[15]
  98
  99#define SRP_PID_FMT "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:" \
 100        "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
 101
 102static ssize_t
 103show_srp_rport_id(struct device *dev, struct device_attribute *attr,
 104                  char *buf)
 105{
 106        struct srp_rport *rport = transport_class_to_srp_rport(dev);
 107        return sprintf(buf, SRP_PID_FMT "\n", SRP_PID(rport));
 108}
 109
 110static DEVICE_ATTR(port_id, S_IRUGO, show_srp_rport_id, NULL);
 111
 112static const struct {
 113        u32 value;
 114        char *name;
 115} srp_rport_role_names[] = {
 116        {SRP_RPORT_ROLE_INITIATOR, "SRP Initiator"},
 117        {SRP_RPORT_ROLE_TARGET, "SRP Target"},
 118};
 119
 120static ssize_t
 121show_srp_rport_roles(struct device *dev, struct device_attribute *attr,
 122                     char *buf)
 123{
 124        struct srp_rport *rport = transport_class_to_srp_rport(dev);
 125        int i;
 126        char *name = NULL;
 127
 128        for (i = 0; i < ARRAY_SIZE(srp_rport_role_names); i++)
 129                if (srp_rport_role_names[i].value == rport->roles) {
 130                        name = srp_rport_role_names[i].name;
 131                        break;
 132                }
 133        return sprintf(buf, "%s\n", name ? : "unknown");
 134}
 135
 136static DEVICE_ATTR(roles, S_IRUGO, show_srp_rport_roles, NULL);
 137
 138static void srp_rport_release(struct device *dev)
 139{
 140        struct srp_rport *rport = dev_to_rport(dev);
 141
 142        put_device(dev->parent);
 143        kfree(rport);
 144}
 145
 146static int scsi_is_srp_rport(const struct device *dev)
 147{
 148        return dev->release == srp_rport_release;
 149}
 150
 151static int srp_rport_match(struct attribute_container *cont,
 152                           struct device *dev)
 153{
 154        struct Scsi_Host *shost;
 155        struct srp_internal *i;
 156
 157        if (!scsi_is_srp_rport(dev))
 158                return 0;
 159
 160        shost = dev_to_shost(dev->parent);
 161        if (!shost->transportt)
 162                return 0;
 163        if (shost->transportt->host_attrs.ac.class != &srp_host_class.class)
 164                return 0;
 165
 166        i = to_srp_internal(shost->transportt);
 167        return &i->rport_attr_cont.ac == cont;
 168}
 169
 170static int srp_host_match(struct attribute_container *cont, struct device *dev)
 171{
 172        struct Scsi_Host *shost;
 173        struct srp_internal *i;
 174
 175        if (!scsi_is_host_device(dev))
 176                return 0;
 177
 178        shost = dev_to_shost(dev);
 179        if (!shost->transportt)
 180                return 0;
 181        if (shost->transportt->host_attrs.ac.class != &srp_host_class.class)
 182                return 0;
 183
 184        i = to_srp_internal(shost->transportt);
 185        return &i->t.host_attrs.ac == cont;
 186}
 187
 188/**
 189 * srp_rport_add - add a SRP remote port to the device hierarchy
 190 * @shost:      scsi host the remote port is connected to.
 191 * @ids:        The port id for the remote port.
 192 *
 193 * Publishes a port to the rest of the system.
 194 */
 195struct srp_rport *srp_rport_add(struct Scsi_Host *shost,
 196                                struct srp_rport_identifiers *ids)
 197{
 198        struct srp_rport *rport;
 199        struct device *parent = &shost->shost_gendev;
 200        int id, ret;
 201
 202        rport = kzalloc(sizeof(*rport), GFP_KERNEL);
 203        if (!rport)
 204                return ERR_PTR(-ENOMEM);
 205
 206        device_initialize(&rport->dev);
 207
 208        rport->dev.parent = get_device(parent);
 209        rport->dev.release = srp_rport_release;
 210
 211        memcpy(rport->port_id, ids->port_id, sizeof(rport->port_id));
 212        rport->roles = ids->roles;
 213
 214        id = atomic_inc_return(&to_srp_host_attrs(shost)->next_port_id);
 215        dev_set_name(&rport->dev, "port-%d:%d", shost->host_no, id);
 216
 217        transport_setup_device(&rport->dev);
 218
 219        ret = device_add(&rport->dev);
 220        if (ret) {
 221                transport_destroy_device(&rport->dev);
 222                put_device(&rport->dev);
 223                return ERR_PTR(ret);
 224        }
 225
 226        if (shost->active_mode & MODE_TARGET &&
 227            ids->roles == SRP_RPORT_ROLE_INITIATOR) {
 228                ret = srp_tgt_it_nexus_create(shost, (unsigned long)rport,
 229                                              rport->port_id);
 230                if (ret) {
 231                        device_del(&rport->dev);
 232                        transport_destroy_device(&rport->dev);
 233                        put_device(&rport->dev);
 234                        return ERR_PTR(ret);
 235                }
 236        }
 237
 238        transport_add_device(&rport->dev);
 239        transport_configure_device(&rport->dev);
 240
 241        return rport;
 242}
 243EXPORT_SYMBOL_GPL(srp_rport_add);
 244
 245/**
 246 * srp_rport_del  -  remove a SRP remote port
 247 * @rport:      SRP remote port to remove
 248 *
 249 * Removes the specified SRP remote port.
 250 */
 251void srp_rport_del(struct srp_rport *rport)
 252{
 253        struct device *dev = &rport->dev;
 254        struct Scsi_Host *shost = dev_to_shost(dev->parent);
 255
 256        if (shost->active_mode & MODE_TARGET &&
 257            rport->roles == SRP_RPORT_ROLE_INITIATOR)
 258                srp_tgt_it_nexus_destroy(shost, (unsigned long)rport);
 259
 260        transport_remove_device(dev);
 261        device_del(dev);
 262        transport_destroy_device(dev);
 263        put_device(dev);
 264}
 265EXPORT_SYMBOL_GPL(srp_rport_del);
 266
 267static int do_srp_rport_del(struct device *dev, void *data)
 268{
 269        if (scsi_is_srp_rport(dev))
 270                srp_rport_del(dev_to_rport(dev));
 271        return 0;
 272}
 273
 274/**
 275 * srp_remove_host  -  tear down a Scsi_Host's SRP data structures
 276 * @shost:      Scsi Host that is torn down
 277 *
 278 * Removes all SRP remote ports for a given Scsi_Host.
 279 * Must be called just before scsi_remove_host for SRP HBAs.
 280 */
 281void srp_remove_host(struct Scsi_Host *shost)
 282{
 283        device_for_each_child(&shost->shost_gendev, NULL, do_srp_rport_del);
 284}
 285EXPORT_SYMBOL_GPL(srp_remove_host);
 286
 287static int srp_tsk_mgmt_response(struct Scsi_Host *shost, u64 nexus, u64 tm_id,
 288                                 int result)
 289{
 290        struct srp_internal *i = to_srp_internal(shost->transportt);
 291        return i->f->tsk_mgmt_response(shost, nexus, tm_id, result);
 292}
 293
 294static int srp_it_nexus_response(struct Scsi_Host *shost, u64 nexus, int result)
 295{
 296        struct srp_internal *i = to_srp_internal(shost->transportt);
 297        return i->f->it_nexus_response(shost, nexus, result);
 298}
 299
 300/**
 301 * srp_attach_transport  -  instantiate SRP transport template
 302 * @ft:         SRP transport class function template
 303 */
 304struct scsi_transport_template *
 305srp_attach_transport(struct srp_function_template *ft)
 306{
 307        int count;
 308        struct srp_internal *i;
 309
 310        i = kzalloc(sizeof(*i), GFP_KERNEL);
 311        if (!i)
 312                return NULL;
 313
 314        i->t.tsk_mgmt_response = srp_tsk_mgmt_response;
 315        i->t.it_nexus_response = srp_it_nexus_response;
 316
 317        i->t.host_size = sizeof(struct srp_host_attrs);
 318        i->t.host_attrs.ac.attrs = &i->host_attrs[0];
 319        i->t.host_attrs.ac.class = &srp_host_class.class;
 320        i->t.host_attrs.ac.match = srp_host_match;
 321        i->host_attrs[0] = NULL;
 322        transport_container_register(&i->t.host_attrs);
 323
 324        i->rport_attr_cont.ac.attrs = &i->rport_attrs[0];
 325        i->rport_attr_cont.ac.class = &srp_rport_class.class;
 326        i->rport_attr_cont.ac.match = srp_rport_match;
 327        transport_container_register(&i->rport_attr_cont);
 328
 329        count = 0;
 330        SETUP_RPORT_ATTRIBUTE_RD(port_id);
 331        SETUP_RPORT_ATTRIBUTE_RD(roles);
 332        i->rport_attrs[count] = NULL;
 333
 334        i->f = ft;
 335
 336        return &i->t;
 337}
 338EXPORT_SYMBOL_GPL(srp_attach_transport);
 339
 340/**
 341 * srp_release_transport  -  release SRP transport template instance
 342 * @t:          transport template instance
 343 */
 344void srp_release_transport(struct scsi_transport_template *t)
 345{
 346        struct srp_internal *i = to_srp_internal(t);
 347
 348        transport_container_unregister(&i->t.host_attrs);
 349        transport_container_unregister(&i->rport_attr_cont);
 350
 351        kfree(i);
 352}
 353EXPORT_SYMBOL_GPL(srp_release_transport);
 354
 355static __init int srp_transport_init(void)
 356{
 357        int ret;
 358
 359        ret = transport_class_register(&srp_host_class);
 360        if (ret)
 361                return ret;
 362        ret = transport_class_register(&srp_rport_class);
 363        if (ret)
 364                goto unregister_host_class;
 365
 366        return 0;
 367unregister_host_class:
 368        transport_class_unregister(&srp_host_class);
 369        return ret;
 370}
 371
 372static void __exit srp_transport_exit(void)
 373{
 374        transport_class_unregister(&srp_host_class);
 375        transport_class_unregister(&srp_rport_class);
 376}
 377
 378MODULE_AUTHOR("FUJITA Tomonori");
 379MODULE_DESCRIPTION("SRP Transport Attributes");
 380MODULE_LICENSE("GPL");
 381
 382module_init(srp_transport_init);
 383module_exit(srp_transport_exit);
 384
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.