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