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 3
  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 transport_container rport_attr_cont;
  51};
  52
  53#define to_srp_internal(tmpl) container_of(tmpl, struct srp_internal, t)
  54
  55#define dev_to_rport(d) container_of(d, struct srp_rport, dev)
  56#define transport_class_to_srp_rport(dev) dev_to_rport((dev)->parent)
  57
  58static int srp_host_setup(struct transport_container *tc, struct device *dev,
  59                          struct device *cdev)
  60{
  61        struct Scsi_Host *shost = dev_to_shost(dev);
  62        struct srp_host_attrs *srp_host = to_srp_host_attrs(shost);
  63
  64        atomic_set(&srp_host->next_port_id, 0);
  65        return 0;
  66}
  67
  68static DECLARE_TRANSPORT_CLASS(srp_host_class, "srp_host", srp_host_setup,
  69                               NULL, NULL);
  70
  71static DECLARE_TRANSPORT_CLASS(srp_rport_class, "srp_remote_ports",
  72                               NULL, NULL, NULL);
  73
  74#define SRP_PID(p) \
  75        (p)->port_id[0], (p)->port_id[1], (p)->port_id[2], (p)->port_id[3], \
  76        (p)->port_id[4], (p)->port_id[5], (p)->port_id[6], (p)->port_id[7], \
  77        (p)->port_id[8], (p)->port_id[9], (p)->port_id[10], (p)->port_id[11], \
  78        (p)->port_id[12], (p)->port_id[13], (p)->port_id[14], (p)->port_id[15]
  79
  80#define SRP_PID_FMT "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:" \
  81        "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
  82
  83static ssize_t
  84show_srp_rport_id(struct device *dev, struct device_attribute *attr,
  85                  char *buf)
  86{
  87        struct srp_rport *rport = transport_class_to_srp_rport(dev);
  88        return sprintf(buf, SRP_PID_FMT "\n", SRP_PID(rport));
  89}
  90
  91static DEVICE_ATTR(port_id, S_IRUGO, show_srp_rport_id, NULL);
  92
  93static const struct {
  94        u32 value;
  95        char *name;
  96} srp_rport_role_names[] = {
  97        {SRP_RPORT_ROLE_INITIATOR, "SRP Initiator"},
  98        {SRP_RPORT_ROLE_TARGET, "SRP Target"},
  99};
 100
 101static ssize_t
 102show_srp_rport_roles(struct device *dev, struct device_attribute *attr,
 103                     char *buf)
 104{
 105        struct srp_rport *rport = transport_class_to_srp_rport(dev);
 106        int i;
 107        char *name = NULL;
 108
 109        for (i = 0; i < ARRAY_SIZE(srp_rport_role_names); i++)
 110                if (srp_rport_role_names[i].value == rport->roles) {
 111                        name = srp_rport_role_names[i].name;
 112                        break;
 113                }
 114        return sprintf(buf, "%s\n", name ? : "unknown");
 115}
 116
 117static DEVICE_ATTR(roles, S_IRUGO, show_srp_rport_roles, NULL);
 118
 119static ssize_t store_srp_rport_delete(struct device *dev,
 120                                      struct device_attribute *attr,
 121                                      const char *buf, size_t count)
 122{
 123        struct srp_rport *rport = transport_class_to_srp_rport(dev);
 124        struct Scsi_Host *shost = dev_to_shost(dev);
 125        struct srp_internal *i = to_srp_internal(shost->transportt);
 126
 127        if (i->f->rport_delete) {
 128                i->f->rport_delete(rport);
 129                return count;
 130        } else {
 131                return -ENOSYS;
 132        }
 133}
 134
 135static DEVICE_ATTR(delete, S_IWUSR, NULL, store_srp_rport_delete);
 136
 137static void srp_rport_release(struct device *dev)
 138{
 139        struct srp_rport *rport = dev_to_rport(dev);
 140
 141        put_device(dev->parent);
 142        kfree(rport);
 143}
 144
 145static int scsi_is_srp_rport(const struct device *dev)
 146{
 147        return dev->release == srp_rport_release;
 148}
 149
 150static int srp_rport_match(struct attribute_container *cont,
 151                           struct device *dev)
 152{
 153        struct Scsi_Host *shost;
 154        struct srp_internal *i;
 155
 156        if (!scsi_is_srp_rport(dev))
 157                return 0;
 158
 159        shost = dev_to_shost(dev->parent);
 160        if (!shost->transportt)
 161                return 0;
 162        if (shost->transportt->host_attrs.ac.class != &srp_host_class.class)
 163                return 0;
 164
 165        i = to_srp_internal(shost->transportt);
 166        return &i->rport_attr_cont.ac == cont;
 167}
 168
 169static int srp_host_match(struct attribute_container *cont, struct device *dev)
 170{
 171        struct Scsi_Host *shost;
 172        struct srp_internal *i;
 173
 174        if (!scsi_is_host_device(dev))
 175                return 0;
 176
 177        shost = dev_to_shost(dev);
 178        if (!shost->transportt)
 179                return 0;
 180        if (shost->transportt->host_attrs.ac.class != &srp_host_class.class)
 181                return 0;
 182
 183        i = to_srp_internal(shost->transportt);
 184        return &i->t.host_attrs.ac == cont;
 185}
 186
 187/**
 188 * srp_rport_add - add a SRP remote port to the device hierarchy
 189 * @shost:      scsi host the remote port is connected to.
 190 * @ids:        The port id for the remote port.
 191 *
 192 * Publishes a port to the rest of the system.
 193 */
 194struct srp_rport *srp_rport_add(struct Scsi_Host *shost,
 195                                struct srp_rport_identifiers *ids)
 196{
 197        struct srp_rport *rport;
 198        struct device *parent = &shost->shost_gendev;
 199        int id, ret;
 200
 201        rport = kzalloc(sizeof(*rport), GFP_KERNEL);
 202        if (!rport)
 203                return ERR_PTR(-ENOMEM);
 204
 205        device_initialize(&rport->dev);
 206
 207        rport->dev.parent = get_device(parent);
 208        rport->dev.release = srp_rport_release;
 209
 210        memcpy(rport->port_id, ids->port_id, sizeof(rport->port_id));
 211        rport->roles = ids->roles;
 212
 213        id = atomic_inc_return(&to_srp_host_attrs(shost)->next_port_id);
 214        dev_set_name(&rport->dev, "port-%d:%d", shost->host_no, id);
 215
 216        transport_setup_device(&rport->dev);
 217
 218        ret = device_add(&rport->dev);
 219        if (ret) {
 220                transport_destroy_device(&rport->dev);
 221                put_device(&rport->dev);
 222                return ERR_PTR(ret);
 223        }
 224
 225        if (shost->active_mode & MODE_TARGET &&
 226            ids->roles == SRP_RPORT_ROLE_INITIATOR) {
 227                ret = srp_tgt_it_nexus_create(shost, (unsigned long)rport,
 228                                              rport->port_id);
 229                if (ret) {
 230                        device_del(&rport->dev);
 231                        transport_destroy_device(&rport->dev);
 232                        put_device(&rport->dev);
 233                        return ERR_PTR(ret);
 234                }
 235        }
 236
 237        transport_add_device(&rport->dev);
 238        transport_configure_device(&rport->dev);
 239
 240        return rport;
 241}
 242EXPORT_SYMBOL_GPL(srp_rport_add);
 243
 244/**
 245 * srp_rport_del  -  remove a SRP remote port
 246 * @rport:      SRP remote port to remove
 247 *
 248 * Removes the specified SRP remote port.
 249 */
 250void srp_rport_del(struct srp_rport *rport)
 251{
 252        struct device *dev = &rport->dev;
 253        struct Scsi_Host *shost = dev_to_shost(dev->parent);
 254
 255        if (shost->active_mode & MODE_TARGET &&
 256            rport->roles == SRP_RPORT_ROLE_INITIATOR)
 257                srp_tgt_it_nexus_destroy(shost, (unsigned long)rport);
 258
 259        transport_remove_device(dev);
 260        device_del(dev);
 261        transport_destroy_device(dev);
 262        put_device(dev);
 263}
 264EXPORT_SYMBOL_GPL(srp_rport_del);
 265
 266static int do_srp_rport_del(struct device *dev, void *data)
 267{
 268        if (scsi_is_srp_rport(dev))
 269                srp_rport_del(dev_to_rport(dev));
 270        return 0;
 271}
 272
 273/**
 274 * srp_remove_host  -  tear down a Scsi_Host's SRP data structures
 275 * @shost:      Scsi Host that is torn down
 276 *
 277 * Removes all SRP remote ports for a given Scsi_Host.
 278 * Must be called just before scsi_remove_host for SRP HBAs.
 279 */
 280void srp_remove_host(struct Scsi_Host *shost)
 281{
 282        device_for_each_child(&shost->shost_gendev, NULL, do_srp_rport_del);
 283}
 284EXPORT_SYMBOL_GPL(srp_remove_host);
 285
 286static int srp_tsk_mgmt_response(struct Scsi_Host *shost, u64 nexus, u64 tm_id,
 287                                 int result)
 288{
 289        struct srp_internal *i = to_srp_internal(shost->transportt);
 290        return i->f->tsk_mgmt_response(shost, nexus, tm_id, result);
 291}
 292
 293static int srp_it_nexus_response(struct Scsi_Host *shost, u64 nexus, int result)
 294{
 295        struct srp_internal *i = to_srp_internal(shost->transportt);
 296        return i->f->it_nexus_response(shost, nexus, result);
 297}
 298
 299/**
 300 * srp_attach_transport  -  instantiate SRP transport template
 301 * @ft:         SRP transport class function template
 302 */
 303struct scsi_transport_template *
 304srp_attach_transport(struct srp_function_template *ft)
 305{
 306        int count;
 307        struct srp_internal *i;
 308
 309        i = kzalloc(sizeof(*i), GFP_KERNEL);
 310        if (!i)
 311                return NULL;
 312
 313        i->t.tsk_mgmt_response = srp_tsk_mgmt_response;
 314        i->t.it_nexus_response = srp_it_nexus_response;
 315
 316        i->t.host_size = sizeof(struct srp_host_attrs);
 317        i->t.host_attrs.ac.attrs = &i->host_attrs[0];
 318        i->t.host_attrs.ac.class = &srp_host_class.class;
 319        i->t.host_attrs.ac.match = srp_host_match;
 320        i->host_attrs[0] = NULL;
 321        transport_container_register(&i->t.host_attrs);
 322
 323        i->rport_attr_cont.ac.attrs = &i->rport_attrs[0];
 324        i->rport_attr_cont.ac.class = &srp_rport_class.class;
 325        i->rport_attr_cont.ac.match = srp_rport_match;
 326
 327        count = 0;
 328        i->rport_attrs[count++] = &dev_attr_port_id;
 329        i->rport_attrs[count++] = &dev_attr_roles;
 330        if (ft->rport_delete)
 331                i->rport_attrs[count++] = &dev_attr_delete;
 332        i->rport_attrs[count++] = NULL;
 333        BUG_ON(count > ARRAY_SIZE(i->rport_attrs));
 334
 335        transport_container_register(&i->rport_attr_cont);
 336
 337        i->f = ft;
 338
 339        return &i->t;
 340}
 341EXPORT_SYMBOL_GPL(srp_attach_transport);
 342
 343/**
 344 * srp_release_transport  -  release SRP transport template instance
 345 * @t:          transport template instance
 346 */
 347void srp_release_transport(struct scsi_transport_template *t)
 348{
 349        struct srp_internal *i = to_srp_internal(t);
 350
 351        transport_container_unregister(&i->t.host_attrs);
 352        transport_container_unregister(&i->rport_attr_cont);
 353
 354        kfree(i);
 355}
 356EXPORT_SYMBOL_GPL(srp_release_transport);
 357
 358static __init int srp_transport_init(void)
 359{
 360        int ret;
 361
 362        ret = transport_class_register(&srp_host_class);
 363        if (ret)
 364                return ret;
 365        ret = transport_class_register(&srp_rport_class);
 366        if (ret)
 367                goto unregister_host_class;
 368
 369        return 0;
 370unregister_host_class:
 371        transport_class_unregister(&srp_host_class);
 372        return ret;
 373}
 374
 375static void __exit srp_transport_exit(void)
 376{
 377        transport_class_unregister(&srp_host_class);
 378        transport_class_unregister(&srp_rport_class);
 379}
 380
 381MODULE_AUTHOR("FUJITA Tomonori");
 382MODULE_DESCRIPTION("SRP Transport Attributes");
 383MODULE_LICENSE("GPL");
 384
 385module_init(srp_transport_init);
 386module_exit(srp_transport_exit);
 387
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.