Commit d0a7e574007fd547d72ec693bfa35778623d0738
Committed by
James Bottomley
1 parent
10c1b88987
Exists in
master
and in
7 other branches
[SCSI] correct transport class abstraction to work outside SCSI
I recently tried to construct a totally generic transport class and found there were certain features missing from the current abstract transport class. Most notable is that you have to hang the data on the class_device but most of the API is framed in terms of the generic device, not the class_device. These changes are two fold - Provide the class_device to all of the setup and configure APIs - Provide and extra API to take the device and the attribute class and return the corresponding class_device Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Showing 6 changed files with 72 additions and 20 deletions Side-by-side Diff
drivers/base/attribute_container.c
... | ... | @@ -58,6 +58,7 @@ |
58 | 58 | { |
59 | 59 | INIT_LIST_HEAD(&cont->node); |
60 | 60 | INIT_LIST_HEAD(&cont->containers); |
61 | + spin_lock_init(&cont->containers_lock); | |
61 | 62 | |
62 | 63 | down(&attribute_container_mutex); |
63 | 64 | list_add_tail(&cont->node, &attribute_container_list); |
64 | 65 | |
... | ... | @@ -77,11 +78,13 @@ |
77 | 78 | { |
78 | 79 | int retval = -EBUSY; |
79 | 80 | down(&attribute_container_mutex); |
81 | + spin_lock(&cont->containers_lock); | |
80 | 82 | if (!list_empty(&cont->containers)) |
81 | 83 | goto out; |
82 | 84 | retval = 0; |
83 | 85 | list_del(&cont->node); |
84 | 86 | out: |
87 | + spin_unlock(&cont->containers_lock); | |
85 | 88 | up(&attribute_container_mutex); |
86 | 89 | return retval; |
87 | 90 | |
88 | 91 | |
... | ... | @@ -151,7 +154,9 @@ |
151 | 154 | fn(cont, dev, &ic->classdev); |
152 | 155 | else |
153 | 156 | attribute_container_add_class_device(&ic->classdev); |
157 | + spin_lock(&cont->containers_lock); | |
154 | 158 | list_add_tail(&ic->node, &cont->containers); |
159 | + spin_unlock(&cont->containers_lock); | |
155 | 160 | } |
156 | 161 | up(&attribute_container_mutex); |
157 | 162 | } |
... | ... | @@ -189,6 +194,7 @@ |
189 | 194 | |
190 | 195 | if (!cont->match(cont, dev)) |
191 | 196 | continue; |
197 | + spin_lock(&cont->containers_lock); | |
192 | 198 | list_for_each_entry_safe(ic, tmp, &cont->containers, node) { |
193 | 199 | if (dev != ic->classdev.dev) |
194 | 200 | continue; |
... | ... | @@ -200,6 +206,7 @@ |
200 | 206 | class_device_unregister(&ic->classdev); |
201 | 207 | } |
202 | 208 | } |
209 | + spin_unlock(&cont->containers_lock); | |
203 | 210 | } |
204 | 211 | up(&attribute_container_mutex); |
205 | 212 | } |
206 | 213 | |
... | ... | @@ -230,10 +237,12 @@ |
230 | 237 | if (!cont->match(cont, dev)) |
231 | 238 | continue; |
232 | 239 | |
240 | + spin_lock(&cont->containers_lock); | |
233 | 241 | list_for_each_entry_safe(ic, tmp, &cont->containers, node) { |
234 | 242 | if (dev == ic->classdev.dev) |
235 | 243 | fn(cont, dev, &ic->classdev); |
236 | 244 | } |
245 | + spin_unlock(&cont->containers_lock); | |
237 | 246 | } |
238 | 247 | up(&attribute_container_mutex); |
239 | 248 | } |
... | ... | @@ -367,6 +376,35 @@ |
367 | 376 | class_device_del(classdev); |
368 | 377 | } |
369 | 378 | EXPORT_SYMBOL_GPL(attribute_container_class_device_del); |
379 | + | |
380 | +/** | |
381 | + * attribute_container_find_class_device - find the corresponding class_device | |
382 | + * | |
383 | + * @cont: the container | |
384 | + * @dev: the generic device | |
385 | + * | |
386 | + * Looks up the device in the container's list of class devices and returns | |
387 | + * the corresponding class_device. | |
388 | + */ | |
389 | +struct class_device * | |
390 | +attribute_container_find_class_device(struct attribute_container *cont, | |
391 | + struct device *dev) | |
392 | +{ | |
393 | + struct class_device *cdev = NULL; | |
394 | + struct internal_container *ic; | |
395 | + | |
396 | + spin_lock(&cont->containers_lock); | |
397 | + list_for_each_entry(ic, &cont->containers, node) { | |
398 | + if (ic->classdev.dev == dev) { | |
399 | + cdev = &ic->classdev; | |
400 | + break; | |
401 | + } | |
402 | + } | |
403 | + spin_unlock(&cont->containers_lock); | |
404 | + | |
405 | + return cdev; | |
406 | +} | |
407 | +EXPORT_SYMBOL_GPL(attribute_container_find_class_device); | |
370 | 408 | |
371 | 409 | int __init |
372 | 410 | attribute_container_init(void) |
drivers/base/transport_class.c
... | ... | @@ -64,7 +64,9 @@ |
64 | 64 | } |
65 | 65 | EXPORT_SYMBOL_GPL(transport_class_unregister); |
66 | 66 | |
67 | -static int anon_transport_dummy_function(struct device *dev) | |
67 | +static int anon_transport_dummy_function(struct transport_container *tc, | |
68 | + struct device *dev, | |
69 | + struct class_device *cdev) | |
68 | 70 | { |
69 | 71 | /* do nothing */ |
70 | 72 | return 0; |
71 | 73 | |
... | ... | @@ -115,9 +117,10 @@ |
115 | 117 | struct class_device *classdev) |
116 | 118 | { |
117 | 119 | struct transport_class *tclass = class_to_transport_class(cont->class); |
120 | + struct transport_container *tcont = attribute_container_to_transport_container(cont); | |
118 | 121 | |
119 | 122 | if (tclass->setup) |
120 | - tclass->setup(dev); | |
123 | + tclass->setup(tcont, dev, classdev); | |
121 | 124 | |
122 | 125 | return 0; |
123 | 126 | } |
124 | 127 | |
125 | 128 | |
... | ... | @@ -178,12 +181,14 @@ |
178 | 181 | EXPORT_SYMBOL_GPL(transport_add_device); |
179 | 182 | |
180 | 183 | static int transport_configure(struct attribute_container *cont, |
181 | - struct device *dev) | |
184 | + struct device *dev, | |
185 | + struct class_device *cdev) | |
182 | 186 | { |
183 | 187 | struct transport_class *tclass = class_to_transport_class(cont->class); |
188 | + struct transport_container *tcont = attribute_container_to_transport_container(cont); | |
184 | 189 | |
185 | 190 | if (tclass->configure) |
186 | - tclass->configure(dev); | |
191 | + tclass->configure(tcont, dev, cdev); | |
187 | 192 | |
188 | 193 | return 0; |
189 | 194 | } |
... | ... | @@ -202,7 +207,7 @@ |
202 | 207 | */ |
203 | 208 | void transport_configure_device(struct device *dev) |
204 | 209 | { |
205 | - attribute_container_trigger(dev, transport_configure); | |
210 | + attribute_container_device_trigger(dev, transport_configure); | |
206 | 211 | } |
207 | 212 | EXPORT_SYMBOL_GPL(transport_configure_device); |
208 | 213 | |
... | ... | @@ -215,7 +220,7 @@ |
215 | 220 | struct transport_class *tclass = class_to_transport_class(cont->class); |
216 | 221 | |
217 | 222 | if (tclass->remove) |
218 | - tclass->remove(dev); | |
223 | + tclass->remove(tcont, dev, classdev); | |
219 | 224 | |
220 | 225 | if (tclass->remove != anon_transport_dummy_function) { |
221 | 226 | if (tcont->statistics) |
drivers/scsi/scsi_transport_fc.c
... | ... | @@ -252,7 +252,8 @@ |
252 | 252 | |
253 | 253 | #define to_fc_internal(tmpl) container_of(tmpl, struct fc_internal, t) |
254 | 254 | |
255 | -static int fc_target_setup(struct device *dev) | |
255 | +static int fc_target_setup(struct transport_container *tc, struct device *dev, | |
256 | + struct class_device *cdev) | |
256 | 257 | { |
257 | 258 | struct scsi_target *starget = to_scsi_target(dev); |
258 | 259 | struct fc_rport *rport = starget_to_rport(starget); |
... | ... | @@ -281,7 +282,8 @@ |
281 | 282 | NULL, |
282 | 283 | NULL); |
283 | 284 | |
284 | -static int fc_host_setup(struct device *dev) | |
285 | +static int fc_host_setup(struct transport_container *tc, struct device *dev, | |
286 | + struct class_device *cdev) | |
285 | 287 | { |
286 | 288 | struct Scsi_Host *shost = dev_to_shost(dev); |
287 | 289 |
drivers/scsi/scsi_transport_spi.c
... | ... | @@ -162,7 +162,8 @@ |
162 | 162 | return SPI_SIGNAL_UNKNOWN; |
163 | 163 | } |
164 | 164 | |
165 | -static int spi_host_setup(struct device *dev) | |
165 | +static int spi_host_setup(struct transport_container *tc, struct device *dev, | |
166 | + struct class_device *cdev) | |
166 | 167 | { |
167 | 168 | struct Scsi_Host *shost = dev_to_shost(dev); |
168 | 169 | |
... | ... | @@ -196,7 +197,9 @@ |
196 | 197 | return &i->t.host_attrs.ac == cont; |
197 | 198 | } |
198 | 199 | |
199 | -static int spi_device_configure(struct device *dev) | |
200 | +static int spi_device_configure(struct transport_container *tc, | |
201 | + struct device *dev, | |
202 | + struct class_device *cdev) | |
200 | 203 | { |
201 | 204 | struct scsi_device *sdev = to_scsi_device(dev); |
202 | 205 | struct scsi_target *starget = sdev->sdev_target; |
... | ... | @@ -214,7 +217,9 @@ |
214 | 217 | return 0; |
215 | 218 | } |
216 | 219 | |
217 | -static int spi_setup_transport_attrs(struct device *dev) | |
220 | +static int spi_setup_transport_attrs(struct transport_container *tc, | |
221 | + struct device *dev, | |
222 | + struct class_device *cdev) | |
218 | 223 | { |
219 | 224 | struct scsi_target *starget = to_scsi_target(dev); |
220 | 225 |
include/linux/attribute_container.h
... | ... | @@ -11,10 +11,12 @@ |
11 | 11 | |
12 | 12 | #include <linux/device.h> |
13 | 13 | #include <linux/list.h> |
14 | +#include <linux/spinlock.h> | |
14 | 15 | |
15 | 16 | struct attribute_container { |
16 | 17 | struct list_head node; |
17 | 18 | struct list_head containers; |
19 | + spinlock_t containers_lock; | |
18 | 20 | struct class *class; |
19 | 21 | struct class_device_attribute **attrs; |
20 | 22 | int (*match)(struct attribute_container *, struct device *); |
... | ... | @@ -62,12 +64,7 @@ |
62 | 64 | struct class_device *classdev); |
63 | 65 | void attribute_container_remove_attrs(struct class_device *classdev); |
64 | 66 | void attribute_container_class_device_del(struct class_device *classdev); |
65 | - | |
66 | - | |
67 | - | |
68 | - | |
69 | - | |
70 | - | |
67 | +struct class_device *attribute_container_find_class_device(struct attribute_container *, struct device *); | |
71 | 68 | struct class_device_attribute **attribute_container_classdev_to_attrs(const struct class_device *classdev); |
72 | 69 | |
73 | 70 | #endif |
include/linux/transport_class.h
... | ... | @@ -12,11 +12,16 @@ |
12 | 12 | #include <linux/device.h> |
13 | 13 | #include <linux/attribute_container.h> |
14 | 14 | |
15 | +struct transport_container; | |
16 | + | |
15 | 17 | struct transport_class { |
16 | 18 | struct class class; |
17 | - int (*setup)(struct device *); | |
18 | - int (*configure)(struct device *); | |
19 | - int (*remove)(struct device *); | |
19 | + int (*setup)(struct transport_container *, struct device *, | |
20 | + struct class_device *); | |
21 | + int (*configure)(struct transport_container *, struct device *, | |
22 | + struct class_device *); | |
23 | + int (*remove)(struct transport_container *, struct device *, | |
24 | + struct class_device *); | |
20 | 25 | }; |
21 | 26 | |
22 | 27 | #define DECLARE_TRANSPORT_CLASS(cls, nm, su, rm, cfg) \ |