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