linux/drivers/base/transport_class.c
<<
>>
Prefs
   1/*
   2 * transport_class.c - implementation of generic transport classes
   3 *                     using attribute_containers
   4 *
   5 * Copyright (c) 2005 - James Bottomley <James.Bottomley@steeleye.com>
   6 *
   7 * This file is licensed under GPLv2
   8 *
   9 * The basic idea here is to allow any "device controller" (which
  10 * would most often be a Host Bus Adapter to use the services of one
  11 * or more tranport classes for performing transport specific
  12 * services.  Transport specific services are things that the generic
  13 * command layer doesn't want to know about (speed settings, line
  14 * condidtioning, etc), but which the user might be interested in.
  15 * Thus, the HBA's use the routines exported by the transport classes
  16 * to perform these functions.  The transport classes export certain
  17 * values to the user via sysfs using attribute containers.
  18 *
  19 * Note: because not every HBA will care about every transport
  20 * attribute, there's a many to one relationship that goes like this:
  21 *
  22 * transport class<-----attribute container<----class device
  23 *
  24 * Usually the attribute container is per-HBA, but the design doesn't
  25 * mandate that.  Although most of the services will be specific to
  26 * the actual external storage connection used by the HBA, the generic
  27 * transport class is framed entirely in terms of generic devices to
  28 * allow it to be used by any physical HBA in the system.
  29 */
  30#include <linux/export.h>
  31#include <linux/attribute_container.h>
  32#include <linux/transport_class.h>
  33
  34/**
  35 * transport_class_register - register an initial transport class
  36 *
  37 * @tclass:     a pointer to the transport class structure to be initialised
  38 *
  39 * The transport class contains an embedded class which is used to
  40 * identify it.  The caller should initialise this structure with
  41 * zeros and then generic class must have been initialised with the
  42 * actual transport class unique name.  There's a macro
  43 * DECLARE_TRANSPORT_CLASS() to do this (declared classes still must
  44 * be registered).
  45 *
  46 * Returns 0 on success or error on failure.
  47 */
  48int transport_class_register(struct transport_class *tclass)
  49{
  50        return class_register(&tclass->class);
  51}
  52EXPORT_SYMBOL_GPL(transport_class_register);
  53
  54/**
  55 * transport_class_unregister - unregister a previously registered class
  56 *
  57 * @tclass: The transport class to unregister
  58 *
  59 * Must be called prior to deallocating the memory for the transport
  60 * class.
  61 */
  62void transport_class_unregister(struct transport_class *tclass)
  63{
  64        class_unregister(&tclass->class);
  65}
  66EXPORT_SYMBOL_GPL(transport_class_unregister);
  67
  68static int anon_transport_dummy_function(struct transport_container *tc,
  69                                         struct device *dev,
  70                                         struct device *cdev)
  71{
  72        /* do nothing */
  73        return 0;
  74}
  75
  76/**
  77 * anon_transport_class_register - register an anonymous class
  78 *
  79 * @atc: The anon transport class to register
  80 *
  81 * The anonymous transport class contains both a transport class and a
  82 * container.  The idea of an anonymous class is that it never
  83 * actually has any device attributes associated with it (and thus
  84 * saves on container storage).  So it can only be used for triggering
  85 * events.  Use prezero and then use DECLARE_ANON_TRANSPORT_CLASS() to
  86 * initialise the anon transport class storage.
  87 */
  88int anon_transport_class_register(struct anon_transport_class *atc)
  89{
  90        int error;
  91        atc->container.class = &atc->tclass.class;
  92        attribute_container_set_no_classdevs(&atc->container);
  93        error = attribute_container_register(&atc->container);
  94        if (error)
  95                return error;
  96        atc->tclass.setup = anon_transport_dummy_function;
  97        atc->tclass.remove = anon_transport_dummy_function;
  98        return 0;
  99}
 100EXPORT_SYMBOL_GPL(anon_transport_class_register);
 101
 102/**
 103 * anon_transport_class_unregister - unregister an anon class
 104 *
 105 * @atc: Pointer to the anon transport class to unregister
 106 *
 107 * Must be called prior to deallocating the memory for the anon
 108 * transport class.
 109 */
 110void anon_transport_class_unregister(struct anon_transport_class *atc)
 111{
 112        if (unlikely(attribute_container_unregister(&atc->container)))
 113                BUG();
 114}
 115EXPORT_SYMBOL_GPL(anon_transport_class_unregister);
 116
 117static int transport_setup_classdev(struct attribute_container *cont,
 118                                    struct device *dev,
 119                                    struct device *classdev)
 120{
 121        struct transport_class *tclass = class_to_transport_class(cont->class);
 122        struct transport_container *tcont = attribute_container_to_transport_container(cont);
 123
 124        if (tclass->setup)
 125                tclass->setup(tcont, dev, classdev);
 126
 127        return 0;
 128}
 129
 130/**
 131 * transport_setup_device - declare a new dev for transport class association but don't make it visible yet.
 132 * @dev: the generic device representing the entity being added
 133 *
 134 * Usually, dev represents some component in the HBA system (either
 135 * the HBA itself or a device remote across the HBA bus).  This
 136 * routine is simply a trigger point to see if any set of transport
 137 * classes wishes to associate with the added device.  This allocates
 138 * storage for the class device and initialises it, but does not yet
 139 * add it to the system or add attributes to it (you do this with
 140 * transport_add_device).  If you have no need for a separate setup
 141 * and add operations, use transport_register_device (see
 142 * transport_class.h).
 143 */
 144
 145void transport_setup_device(struct device *dev)
 146{
 147        attribute_container_add_device(dev, transport_setup_classdev);
 148}
 149EXPORT_SYMBOL_GPL(transport_setup_device);
 150
 151static int transport_add_class_device(struct attribute_container *cont,
 152                                      struct device *dev,
 153                                      struct device *classdev)
 154{
 155        int error = attribute_container_add_class_device(classdev);
 156        struct transport_container *tcont = 
 157                attribute_container_to_transport_container(cont);
 158
 159        if (!error && tcont->statistics)
 160                error = sysfs_create_group(&classdev->kobj, tcont->statistics);
 161
 162        return error;
 163}
 164
 165
 166/**
 167 * transport_add_device - declare a new dev for transport class association
 168 *
 169 * @dev: the generic device representing the entity being added
 170 *
 171 * Usually, dev represents some component in the HBA system (either
 172 * the HBA itself or a device remote across the HBA bus).  This
 173 * routine is simply a trigger point used to add the device to the
 174 * system and register attributes for it.
 175 */
 176
 177void transport_add_device(struct device *dev)
 178{
 179        attribute_container_device_trigger(dev, transport_add_class_device);
 180}
 181EXPORT_SYMBOL_GPL(transport_add_device);
 182
 183static int transport_configure(struct attribute_container *cont,
 184                               struct device *dev,
 185                               struct device *cdev)
 186{
 187        struct transport_class *tclass = class_to_transport_class(cont->class);
 188        struct transport_container *tcont = attribute_container_to_transport_container(cont);
 189
 190        if (tclass->configure)
 191                tclass->configure(tcont, dev, cdev);
 192
 193        return 0;
 194}
 195
 196/**
 197 * transport_configure_device - configure an already set up device
 198 *
 199 * @dev: generic device representing device to be configured
 200 *
 201 * The idea of configure is simply to provide a point within the setup
 202 * process to allow the transport class to extract information from a
 203 * device after it has been setup.  This is used in SCSI because we
 204 * have to have a setup device to begin using the HBA, but after we
 205 * send the initial inquiry, we use configure to extract the device
 206 * parameters.  The device need not have been added to be configured.
 207 */
 208void transport_configure_device(struct device *dev)
 209{
 210        attribute_container_device_trigger(dev, transport_configure);
 211}
 212EXPORT_SYMBOL_GPL(transport_configure_device);
 213
 214static int transport_remove_classdev(struct attribute_container *cont,
 215                                     struct device *dev,
 216                                     struct device *classdev)
 217{
 218        struct transport_container *tcont = 
 219                attribute_container_to_transport_container(cont);
 220        struct transport_class *tclass = class_to_transport_class(cont->class);
 221
 222        if (tclass->remove)
 223                tclass->remove(tcont, dev, classdev);
 224
 225        if (tclass->remove != anon_transport_dummy_function) {
 226                if (tcont->statistics)
 227                        sysfs_remove_group(&classdev->kobj, tcont->statistics);
 228                attribute_container_class_device_del(classdev);
 229        }
 230
 231        return 0;
 232}
 233
 234
 235/**
 236 * transport_remove_device - remove the visibility of a device
 237 *
 238 * @dev: generic device to remove
 239 *
 240 * This call removes the visibility of the device (to the user from
 241 * sysfs), but does not destroy it.  To eliminate a device entirely
 242 * you must also call transport_destroy_device.  If you don't need to
 243 * do remove and destroy as separate operations, use
 244 * transport_unregister_device() (see transport_class.h) which will
 245 * perform both calls for you.
 246 */
 247void transport_remove_device(struct device *dev)
 248{
 249        attribute_container_device_trigger(dev, transport_remove_classdev);
 250}
 251EXPORT_SYMBOL_GPL(transport_remove_device);
 252
 253static void transport_destroy_classdev(struct attribute_container *cont,
 254                                      struct device *dev,
 255                                      struct device *classdev)
 256{
 257        struct transport_class *tclass = class_to_transport_class(cont->class);
 258
 259        if (tclass->remove != anon_transport_dummy_function)
 260                put_device(classdev);
 261}
 262
 263
 264/**
 265 * transport_destroy_device - destroy a removed device
 266 *
 267 * @dev: device to eliminate from the transport class.
 268 *
 269 * This call triggers the elimination of storage associated with the
 270 * transport classdev.  Note: all it really does is relinquish a
 271 * reference to the classdev.  The memory will not be freed until the
 272 * last reference goes to zero.  Note also that the classdev retains a
 273 * reference count on dev, so dev too will remain for as long as the
 274 * transport class device remains around.
 275 */
 276void transport_destroy_device(struct device *dev)
 277{
 278        attribute_container_remove_device(dev, transport_destroy_classdev);
 279}
 280EXPORT_SYMBOL_GPL(transport_destroy_device);
 281