aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2005-09-09 10:22:50 -0400
committerJames Bottomley <jejb@mulgrave.(none)>2005-09-09 17:43:37 -0400
commitc7ebbbce366c02e5657ac6b6059933fe0353b175 (patch)
treefd4476e249d27218a35c1807323b5d064c45f8b3 /drivers
parent942fc2fb73f2cac53484ebaf1c4f9af7aefaca83 (diff)
[SCSI] SAS transport class
The SAS transport class contains common code to deal with SAS HBAs, an aproximated representation of SAS topologies in the driver model, and various sysfs attributes to expose these topologies and managment interfaces to userspace. In addition to the basic SCSI core objects this transport class introduces two additional intermediate objects: The SAS PHY as represented by struct sas_phy defines an "outgoing" PHY on a SAS HBA or Expander, and the SAS remote PHY represented by struct sas_rphy defines an "incoming" PHY on a SAS Expander or end device. Note that this is purely a software concept, the underlying hardware for a PHY and a remote PHY is the exactly the same. There is no concept of a SAS port in this code, users can see what PHYs form a wide port based on the port_identifier attribute, which is the same for all PHYs in a port. This submission doesn't handle hot-plug addition or removal of SAS devices and thus doesn't do scanning in a workqueue yet, that will be added in phase2 after this submission. In a third phase I will add additional managment infrastructure. I think this submission is ready for 2.6.14, but additional comments are of course very welcome. I'd like to thanks James Smart a lot for his very useful input on the design. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/scsi/Kconfig7
-rw-r--r--drivers/scsi/Makefile1
-rw-r--r--drivers/scsi/scsi_transport_sas.c819
3 files changed, 827 insertions, 0 deletions
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 2d21265e650b..20019b82b4a8 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -235,6 +235,13 @@ config SCSI_ISCSI_ATTRS
235 each attached iSCSI device to sysfs, say Y. 235 each attached iSCSI device to sysfs, say Y.
236 Otherwise, say N. 236 Otherwise, say N.
237 237
238config SCSI_SAS_ATTRS
239 tristate "SAS Transport Attributes"
240 depends on SCSI
241 help
242 If you wish to export transport-specific information about
243 each attached SAS device to sysfs, say Y.
244
238endmenu 245endmenu
239 246
240menu "SCSI low-level drivers" 247menu "SCSI low-level drivers"
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 4b4fd94c2674..1e4edbdf2730 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -31,6 +31,7 @@ obj-$(CONFIG_RAID_ATTRS) += raid_class.o
31obj-$(CONFIG_SCSI_SPI_ATTRS) += scsi_transport_spi.o 31obj-$(CONFIG_SCSI_SPI_ATTRS) += scsi_transport_spi.o
32obj-$(CONFIG_SCSI_FC_ATTRS) += scsi_transport_fc.o 32obj-$(CONFIG_SCSI_FC_ATTRS) += scsi_transport_fc.o
33obj-$(CONFIG_SCSI_ISCSI_ATTRS) += scsi_transport_iscsi.o 33obj-$(CONFIG_SCSI_ISCSI_ATTRS) += scsi_transport_iscsi.o
34obj-$(CONFIG_SCSI_SAS_ATTRS) += scsi_transport_sas.o
34 35
35obj-$(CONFIG_SCSI_AMIGA7XX) += amiga7xx.o 53c7xx.o 36obj-$(CONFIG_SCSI_AMIGA7XX) += amiga7xx.o 53c7xx.o
36obj-$(CONFIG_A3000_SCSI) += a3000.o wd33c93.o 37obj-$(CONFIG_A3000_SCSI) += a3000.o wd33c93.o
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
new file mode 100644
index 000000000000..ac4a53a019c0
--- /dev/null
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -0,0 +1,819 @@
1/*
2 * Copyright (C) 2005 Dell Inc.
3 * Released under GPL v2.
4 *
5 * Serial Attached SCSI (SAS) transport class.
6 *
7 * The SAS transport class contains common code to deal with SAS HBAs,
8 * an aproximated representation of SAS topologies in the driver model,
9 * and various sysfs attributes to expose these topologies and managment
10 * interfaces to userspace.
11 *
12 * In addition to the basic SCSI core objects this transport class
13 * introduces two additional intermediate objects: The SAS PHY
14 * as represented by struct sas_phy defines an "outgoing" PHY on
15 * a SAS HBA or Expander, and the SAS remote PHY represented by
16 * struct sas_rphy defines an "incoming" PHY on a SAS Expander or
17 * end device. Note that this is purely a software concept, the
18 * underlying hardware for a PHY and a remote PHY is the exactly
19 * the same.
20 *
21 * There is no concept of a SAS port in this code, users can see
22 * what PHYs form a wide port based on the port_identifier attribute,
23 * which is the same for all PHYs in a port.
24 */
25
26#include <linux/init.h>
27#include <linux/module.h>
28#include <linux/err.h>
29
30#include <scsi/scsi_device.h>
31#include <scsi/scsi_host.h>
32#include <scsi/scsi_transport.h>
33#include <scsi/scsi_transport_sas.h>
34
35
36#define SAS_HOST_ATTRS 0
37#define SAS_PORT_ATTRS 11
38#define SAS_RPORT_ATTRS 5
39
40struct sas_internal {
41 struct scsi_transport_template t;
42 struct sas_function_template *f;
43
44 struct class_device_attribute private_host_attrs[SAS_HOST_ATTRS];
45 struct class_device_attribute private_phy_attrs[SAS_PORT_ATTRS];
46 struct class_device_attribute private_rphy_attrs[SAS_RPORT_ATTRS];
47
48 struct transport_container phy_attr_cont;
49 struct transport_container rphy_attr_cont;
50
51 /*
52 * The array of null terminated pointers to attributes
53 * needed by scsi_sysfs.c
54 */
55 struct class_device_attribute *host_attrs[SAS_HOST_ATTRS + 1];
56 struct class_device_attribute *phy_attrs[SAS_PORT_ATTRS + 1];
57 struct class_device_attribute *rphy_attrs[SAS_RPORT_ATTRS + 1];
58};
59#define to_sas_internal(tmpl) container_of(tmpl, struct sas_internal, t)
60
61struct sas_host_attrs {
62 struct list_head rphy_list;
63 spinlock_t lock;
64 u32 next_target_id;
65};
66#define to_sas_host_attrs(host) ((struct sas_host_attrs *)(host)->shost_data)
67
68
69/*
70 * Hack to allow attributes of the same name in different objects.
71 */
72#define SAS_CLASS_DEVICE_ATTR(_prefix,_name,_mode,_show,_store) \
73 struct class_device_attribute class_device_attr_##_prefix##_##_name = \
74 __ATTR(_name,_mode,_show,_store)
75
76
77/*
78 * Pretty printing helpers
79 */
80
81#define sas_bitfield_name_match(title, table) \
82static ssize_t \
83get_sas_##title##_names(u32 table_key, char *buf) \
84{ \
85 char *prefix = ""; \
86 ssize_t len = 0; \
87 int i; \
88 \
89 for (i = 0; i < sizeof(table)/sizeof(table[0]); i++) { \
90 if (table[i].value & table_key) { \
91 len += sprintf(buf + len, "%s%s", \
92 prefix, table[i].name); \
93 prefix = ", "; \
94 } \
95 } \
96 len += sprintf(buf + len, "\n"); \
97 return len; \
98}
99
100#define sas_bitfield_name_search(title, table) \
101static ssize_t \
102get_sas_##title##_names(u32 table_key, char *buf) \
103{ \
104 ssize_t len = 0; \
105 int i; \
106 \
107 for (i = 0; i < sizeof(table)/sizeof(table[0]); i++) { \
108 if (table[i].value == table_key) { \
109 len += sprintf(buf + len, "%s", \
110 table[i].name); \
111 break; \
112 } \
113 } \
114 len += sprintf(buf + len, "\n"); \
115 return len; \
116}
117
118static struct {
119 u32 value;
120 char *name;
121} sas_device_type_names[] = {
122 { SAS_PHY_UNUSED, "unused" },
123 { SAS_END_DEVICE, "end device" },
124 { SAS_EDGE_EXPANDER_DEVICE, "edge expander" },
125 { SAS_FANOUT_EXPANDER_DEVICE, "fanout expander" },
126};
127sas_bitfield_name_search(device_type, sas_device_type_names)
128
129
130static struct {
131 u32 value;
132 char *name;
133} sas_protocol_names[] = {
134 { SAS_PROTOCOL_SATA, "sata" },
135 { SAS_PROTOCOL_SMP, "smp" },
136 { SAS_PROTOCOL_STP, "stp" },
137 { SAS_PROTOCOL_SSP, "ssp" },
138};
139sas_bitfield_name_match(protocol, sas_protocol_names)
140
141static struct {
142 u32 value;
143 char *name;
144} sas_linkspeed_names[] = {
145 { SAS_LINK_RATE_UNKNOWN, "Unknown" },
146 { SAS_PHY_DISABLED, "Phy disabled" },
147 { SAS_LINK_RATE_FAILED, "Link Rate failed" },
148 { SAS_SATA_SPINUP_HOLD, "Spin-up hold" },
149 { SAS_LINK_RATE_1_5_GBPS, "1.5 Gbit" },
150 { SAS_LINK_RATE_3_0_GBPS, "3.0 Gbit" },
151};
152sas_bitfield_name_search(linkspeed, sas_linkspeed_names)
153
154
155/*
156 * SAS host attributes
157 */
158
159static int sas_host_setup(struct device *dev)
160{
161 struct Scsi_Host *shost = dev_to_shost(dev);
162 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
163
164 INIT_LIST_HEAD(&sas_host->rphy_list);
165 spin_lock_init(&sas_host->lock);
166 sas_host->next_target_id = 0;
167 return 0;
168}
169
170static DECLARE_TRANSPORT_CLASS(sas_host_class,
171 "sas_host", sas_host_setup, NULL, NULL);
172
173static int sas_host_match(struct attribute_container *cont,
174 struct device *dev)
175{
176 struct Scsi_Host *shost;
177 struct sas_internal *i;
178
179 if (!scsi_is_host_device(dev))
180 return 0;
181 shost = dev_to_shost(dev);
182
183 if (!shost->transportt)
184 return 0;
185 if (shost->transportt->host_attrs.ac.class !=
186 &sas_host_class.class)
187 return 0;
188
189 i = to_sas_internal(shost->transportt);
190 return &i->t.host_attrs.ac == cont;
191}
192
193static int do_sas_phy_delete(struct device *dev, void *data)
194{
195 if (scsi_is_sas_phy(dev))
196 sas_phy_delete(dev_to_phy(dev));
197 return 0;
198}
199
200/**
201 * sas_remove_host -- tear down a Scsi_Host's SAS data structures
202 * @shost: Scsi Host that is torn down
203 *
204 * Removes all SAS PHYs and remote PHYs for a given Scsi_Host.
205 * Must be called just before scsi_remove_host for SAS HBAs.
206 */
207void sas_remove_host(struct Scsi_Host *shost)
208{
209 device_for_each_child(&shost->shost_gendev, NULL, do_sas_phy_delete);
210}
211EXPORT_SYMBOL(sas_remove_host);
212
213
214/*
215 * SAS Port attributes
216 */
217
218#define sas_phy_show_simple(field, name, format_string, cast) \
219static ssize_t \
220show_sas_phy_##name(struct class_device *cdev, char *buf) \
221{ \
222 struct sas_phy *phy = transport_class_to_phy(cdev); \
223 \
224 return snprintf(buf, 20, format_string, cast phy->field); \
225}
226
227#define sas_phy_simple_attr(field, name, format_string, type) \
228 sas_phy_show_simple(field, name, format_string, (type)) \
229static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL)
230
231#define sas_phy_show_protocol(field, name) \
232static ssize_t \
233show_sas_phy_##name(struct class_device *cdev, char *buf) \
234{ \
235 struct sas_phy *phy = transport_class_to_phy(cdev); \
236 \
237 if (!phy->field) \
238 return snprintf(buf, 20, "none\n"); \
239 return get_sas_protocol_names(phy->field, buf); \
240}
241
242#define sas_phy_protocol_attr(field, name) \
243 sas_phy_show_protocol(field, name) \
244static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL)
245
246#define sas_phy_show_linkspeed(field) \
247static ssize_t \
248show_sas_phy_##field(struct class_device *cdev, char *buf) \
249{ \
250 struct sas_phy *phy = transport_class_to_phy(cdev); \
251 \
252 return get_sas_linkspeed_names(phy->field, buf); \
253}
254
255#define sas_phy_linkspeed_attr(field) \
256 sas_phy_show_linkspeed(field) \
257static CLASS_DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL)
258
259static ssize_t
260show_sas_device_type(struct class_device *cdev, char *buf)
261{
262 struct sas_phy *phy = transport_class_to_phy(cdev);
263
264 if (!phy->identify.device_type)
265 return snprintf(buf, 20, "none\n");
266 return get_sas_device_type_names(phy->identify.device_type, buf);
267}
268
269static CLASS_DEVICE_ATTR(device_type, S_IRUGO, show_sas_device_type, NULL);
270
271sas_phy_protocol_attr(identify.initiator_port_protocols,
272 initiator_port_protocols);
273sas_phy_protocol_attr(identify.target_port_protocols,
274 target_port_protocols);
275sas_phy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n",
276 unsigned long long);
277sas_phy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8);
278sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", u8);
279sas_phy_linkspeed_attr(negotiated_linkrate);
280sas_phy_linkspeed_attr(minimum_linkrate_hw);
281sas_phy_linkspeed_attr(minimum_linkrate);
282sas_phy_linkspeed_attr(maximum_linkrate_hw);
283sas_phy_linkspeed_attr(maximum_linkrate);
284
285
286static DECLARE_TRANSPORT_CLASS(sas_phy_class,
287 "sas_phy", NULL, NULL, NULL);
288
289static int sas_phy_match(struct attribute_container *cont, struct device *dev)
290{
291 struct Scsi_Host *shost;
292 struct sas_internal *i;
293
294 if (!scsi_is_sas_phy(dev))
295 return 0;
296 shost = dev_to_shost(dev->parent);
297
298 if (!shost->transportt)
299 return 0;
300 if (shost->transportt->host_attrs.ac.class !=
301 &sas_host_class.class)
302 return 0;
303
304 i = to_sas_internal(shost->transportt);
305 return &i->phy_attr_cont.ac == cont;
306}
307
308static void sas_phy_release(struct device *dev)
309{
310 struct sas_phy *phy = dev_to_phy(dev);
311
312 put_device(dev->parent);
313 kfree(phy);
314}
315
316/**
317 * sas_phy_alloc -- allocates and initialize a SAS PHY structure
318 * @parent: Parent device
319 * @number: Port number
320 *
321 * Allocates an SAS PHY structure. It will be added in the device tree
322 * below the device specified by @parent, which has to be either a Scsi_Host
323 * or sas_rphy.
324 *
325 * Returns:
326 * SAS PHY allocated or %NULL if the allocation failed.
327 */
328struct sas_phy *sas_phy_alloc(struct device *parent, int number)
329{
330 struct Scsi_Host *shost = dev_to_shost(parent);
331 struct sas_phy *phy;
332
333 phy = kmalloc(sizeof(*phy), GFP_KERNEL);
334 if (!phy)
335 return NULL;
336 memset(phy, 0, sizeof(*phy));
337
338 get_device(parent);
339
340 phy->number = number;
341
342 device_initialize(&phy->dev);
343 phy->dev.parent = get_device(parent);
344 phy->dev.release = sas_phy_release;
345 sprintf(phy->dev.bus_id, "phy-%d:%d", shost->host_no, number);
346
347 transport_setup_device(&phy->dev);
348
349 return phy;
350}
351EXPORT_SYMBOL(sas_phy_alloc);
352
353/**
354 * sas_phy_add -- add a SAS PHY to the device hierachy
355 * @phy: The PHY to be added
356 *
357 * Publishes a SAS PHY to the rest of the system.
358 */
359int sas_phy_add(struct sas_phy *phy)
360{
361 int error;
362
363 error = device_add(&phy->dev);
364 if (!error) {
365 transport_add_device(&phy->dev);
366 transport_configure_device(&phy->dev);
367 }
368
369 return error;
370}
371EXPORT_SYMBOL(sas_phy_add);
372
373/**
374 * sas_phy_free -- free a SAS PHY
375 * @phy: SAS PHY to free
376 *
377 * Frees the specified SAS PHY.
378 *
379 * Note:
380 * This function must only be called on a PHY that has not
381 * sucessfully been added using sas_phy_add().
382 */
383void sas_phy_free(struct sas_phy *phy)
384{
385 transport_destroy_device(&phy->dev);
386 put_device(phy->dev.parent);
387 put_device(phy->dev.parent);
388 put_device(phy->dev.parent);
389 kfree(phy);
390}
391EXPORT_SYMBOL(sas_phy_free);
392
393/**
394 * sas_phy_delete -- remove SAS PHY
395 * @phy: SAS PHY to remove
396 *
397 * Removes the specified SAS PHY. If the SAS PHY has an
398 * associated remote PHY it is removed before.
399 */
400void
401sas_phy_delete(struct sas_phy *phy)
402{
403 struct device *dev = &phy->dev;
404
405 if (phy->rphy)
406 sas_rphy_delete(phy->rphy);
407
408 transport_remove_device(dev);
409 device_del(dev);
410 transport_destroy_device(dev);
411 put_device(dev->parent);
412}
413EXPORT_SYMBOL(sas_phy_delete);
414
415/**
416 * scsi_is_sas_phy -- check if a struct device represents a SAS PHY
417 * @dev: device to check
418 *
419 * Returns:
420 * %1 if the device represents a SAS PHY, %0 else
421 */
422int scsi_is_sas_phy(const struct device *dev)
423{
424 return dev->release == sas_phy_release;
425}
426EXPORT_SYMBOL(scsi_is_sas_phy);
427
428/*
429 * SAS remote PHY attributes.
430 */
431
432#define sas_rphy_show_simple(field, name, format_string, cast) \
433static ssize_t \
434show_sas_rphy_##name(struct class_device *cdev, char *buf) \
435{ \
436 struct sas_rphy *rphy = transport_class_to_rphy(cdev); \
437 \
438 return snprintf(buf, 20, format_string, cast rphy->field); \
439}
440
441#define sas_rphy_simple_attr(field, name, format_string, type) \
442 sas_rphy_show_simple(field, name, format_string, (type)) \
443static SAS_CLASS_DEVICE_ATTR(rphy, name, S_IRUGO, \
444 show_sas_rphy_##name, NULL)
445
446#define sas_rphy_show_protocol(field, name) \
447static ssize_t \
448show_sas_rphy_##name(struct class_device *cdev, char *buf) \
449{ \
450 struct sas_rphy *rphy = transport_class_to_rphy(cdev); \
451 \
452 if (!rphy->field) \
453 return snprintf(buf, 20, "none\n"); \
454 return get_sas_protocol_names(rphy->field, buf); \
455}
456
457#define sas_rphy_protocol_attr(field, name) \
458 sas_rphy_show_protocol(field, name) \
459static SAS_CLASS_DEVICE_ATTR(rphy, name, S_IRUGO, \
460 show_sas_rphy_##name, NULL)
461
462static ssize_t
463show_sas_rphy_device_type(struct class_device *cdev, char *buf)
464{
465 struct sas_rphy *rphy = transport_class_to_rphy(cdev);
466
467 if (!rphy->identify.device_type)
468 return snprintf(buf, 20, "none\n");
469 return get_sas_device_type_names(
470 rphy->identify.device_type, buf);
471}
472
473static SAS_CLASS_DEVICE_ATTR(rphy, device_type, S_IRUGO,
474 show_sas_rphy_device_type, NULL);
475
476sas_rphy_protocol_attr(identify.initiator_port_protocols,
477 initiator_port_protocols);
478sas_rphy_protocol_attr(identify.target_port_protocols, target_port_protocols);
479sas_rphy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n",
480 unsigned long long);
481sas_rphy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8);
482
483static DECLARE_TRANSPORT_CLASS(sas_rphy_class,
484 "sas_rphy", NULL, NULL, NULL);
485
486static int sas_rphy_match(struct attribute_container *cont, struct device *dev)
487{
488 struct Scsi_Host *shost;
489 struct sas_internal *i;
490
491 if (!scsi_is_sas_rphy(dev))
492 return 0;
493 shost = dev_to_shost(dev->parent->parent);
494
495 if (!shost->transportt)
496 return 0;
497 if (shost->transportt->host_attrs.ac.class !=
498 &sas_host_class.class)
499 return 0;
500
501 i = to_sas_internal(shost->transportt);
502 return &i->rphy_attr_cont.ac == cont;
503}
504
505static void sas_rphy_release(struct device *dev)
506{
507 struct sas_rphy *rphy = dev_to_rphy(dev);
508
509 put_device(dev->parent);
510 kfree(rphy);
511}
512
513/**
514 * sas_rphy_alloc -- allocates and initialize a SAS remote PHY structure
515 * @parent: SAS PHY this remote PHY is conneted to
516 *
517 * Allocates an SAS remote PHY structure, connected to @parent.
518 *
519 * Returns:
520 * SAS PHY allocated or %NULL if the allocation failed.
521 */
522struct sas_rphy *sas_rphy_alloc(struct sas_phy *parent)
523{
524 struct Scsi_Host *shost = dev_to_shost(&parent->dev);
525 struct sas_rphy *rphy;
526
527 rphy = kmalloc(sizeof(*rphy), GFP_KERNEL);
528 if (!rphy) {
529 put_device(&parent->dev);
530 return NULL;
531 }
532 memset(rphy, 0, sizeof(*rphy));
533
534 device_initialize(&rphy->dev);
535 rphy->dev.parent = get_device(&parent->dev);
536 rphy->dev.release = sas_rphy_release;
537 sprintf(rphy->dev.bus_id, "rphy-%d:%d",
538 shost->host_no, parent->number);
539 transport_setup_device(&rphy->dev);
540
541 return rphy;
542}
543EXPORT_SYMBOL(sas_rphy_alloc);
544
545/**
546 * sas_rphy_add -- add a SAS remote PHY to the device hierachy
547 * @rphy: The remote PHY to be added
548 *
549 * Publishes a SAS remote PHY to the rest of the system.
550 */
551int sas_rphy_add(struct sas_rphy *rphy)
552{
553 struct sas_phy *parent = dev_to_phy(rphy->dev.parent);
554 struct Scsi_Host *shost = dev_to_shost(parent->dev.parent);
555 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
556 struct sas_identify *identify = &rphy->identify;
557 int error;
558
559 if (parent->rphy)
560 return -ENXIO;
561 parent->rphy = rphy;
562
563 error = device_add(&rphy->dev);
564 if (error)
565 return error;
566 transport_add_device(&rphy->dev);
567 transport_configure_device(&rphy->dev);
568
569 spin_lock(&sas_host->lock);
570 list_add_tail(&rphy->list, &sas_host->rphy_list);
571 if (identify->device_type == SAS_END_DEVICE &&
572 (identify->target_port_protocols &
573 (SAS_PROTOCOL_SSP|SAS_PROTOCOL_STP|SAS_PROTOCOL_SATA)))
574 rphy->scsi_target_id = sas_host->next_target_id++;
575 else
576 rphy->scsi_target_id = -1;
577 spin_unlock(&sas_host->lock);
578
579 if (rphy->scsi_target_id != -1) {
580 scsi_scan_target(&rphy->dev, parent->number,
581 rphy->scsi_target_id, ~0, 0);
582 }
583
584 return 0;
585}
586EXPORT_SYMBOL(sas_rphy_add);
587
588/**
589 * sas_rphy_free -- free a SAS remote PHY
590 * @rphy SAS remote PHY to free
591 *
592 * Frees the specified SAS remote PHY.
593 *
594 * Note:
595 * This function must only be called on a remote
596 * PHY that has not sucessfully been added using
597 * sas_rphy_add().
598 */
599void sas_rphy_free(struct sas_rphy *rphy)
600{
601 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
602 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
603
604 spin_lock(&sas_host->lock);
605 list_del(&rphy->list);
606 spin_unlock(&sas_host->lock);
607
608 transport_destroy_device(&rphy->dev);
609 put_device(rphy->dev.parent);
610 put_device(rphy->dev.parent);
611 put_device(rphy->dev.parent);
612 kfree(rphy);
613}
614EXPORT_SYMBOL(sas_rphy_free);
615
616/**
617 * sas_rphy_delete -- remove SAS remote PHY
618 * @rphy: SAS remote PHY to remove
619 *
620 * Removes the specified SAS remote PHY.
621 */
622void
623sas_rphy_delete(struct sas_rphy *rphy)
624{
625 struct device *dev = &rphy->dev;
626 struct sas_phy *parent = dev_to_phy(dev->parent);
627 struct Scsi_Host *shost = dev_to_shost(parent->dev.parent);
628 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
629
630 transport_destroy_device(&rphy->dev);
631
632 scsi_remove_target(&rphy->dev);
633
634 spin_lock(&sas_host->lock);
635 list_del(&rphy->list);
636 spin_unlock(&sas_host->lock);
637
638 transport_remove_device(dev);
639 device_del(dev);
640 transport_destroy_device(dev);
641 put_device(&parent->dev);
642}
643EXPORT_SYMBOL(sas_rphy_delete);
644
645/**
646 * scsi_is_sas_rphy -- check if a struct device represents a SAS remote PHY
647 * @dev: device to check
648 *
649 * Returns:
650 * %1 if the device represents a SAS remote PHY, %0 else
651 */
652int scsi_is_sas_rphy(const struct device *dev)
653{
654 return dev->release == sas_rphy_release;
655}
656EXPORT_SYMBOL(scsi_is_sas_rphy);
657
658
659/*
660 * SCSI scan helper
661 */
662
663static struct device *sas_target_parent(struct Scsi_Host *shost,
664 int channel, uint id)
665{
666 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
667 struct sas_rphy *rphy;
668 struct device *dev = NULL;
669
670 spin_lock(&sas_host->lock);
671 list_for_each_entry(rphy, &sas_host->rphy_list, list) {
672 struct sas_phy *parent = dev_to_phy(rphy->dev.parent);
673 if (parent->number == channel &&
674 rphy->scsi_target_id == id)
675 dev = &rphy->dev;
676 }
677 spin_unlock(&sas_host->lock);
678
679 return dev;
680}
681
682
683/*
684 * Setup / Teardown code
685 */
686
687#define SETUP_RPORT_ATTRIBUTE(field) \
688 i->private_rphy_attrs[count] = class_device_attr_##field; \
689 i->private_rphy_attrs[count].attr.mode = S_IRUGO; \
690 i->private_rphy_attrs[count].store = NULL; \
691 i->rphy_attrs[count] = &i->private_rphy_attrs[count]; \
692 count++
693
694#define SETUP_PORT_ATTRIBUTE(field) \
695 i->private_phy_attrs[count] = class_device_attr_##field; \
696 i->private_phy_attrs[count].attr.mode = S_IRUGO; \
697 i->private_phy_attrs[count].store = NULL; \
698 i->phy_attrs[count] = &i->private_phy_attrs[count]; \
699 count++
700
701
702/**
703 * sas_attach_transport -- instantiate SAS transport template
704 * @ft: SAS transport class function template
705 */
706struct scsi_transport_template *
707sas_attach_transport(struct sas_function_template *ft)
708{
709 struct sas_internal *i;
710 int count;
711
712 i = kmalloc(sizeof(struct sas_internal), GFP_KERNEL);
713 if (!i)
714 return NULL;
715 memset(i, 0, sizeof(struct sas_internal));
716
717 i->t.target_parent = sas_target_parent;
718
719 i->t.host_attrs.ac.attrs = &i->host_attrs[0];
720 i->t.host_attrs.ac.class = &sas_host_class.class;
721 i->t.host_attrs.ac.match = sas_host_match;
722 transport_container_register(&i->t.host_attrs);
723 i->t.host_size = sizeof(struct sas_host_attrs);
724
725 i->phy_attr_cont.ac.class = &sas_phy_class.class;
726 i->phy_attr_cont.ac.attrs = &i->phy_attrs[0];
727 i->phy_attr_cont.ac.match = sas_phy_match;
728 transport_container_register(&i->phy_attr_cont);
729
730 i->rphy_attr_cont.ac.class = &sas_rphy_class.class;
731 i->rphy_attr_cont.ac.attrs = &i->rphy_attrs[0];
732 i->rphy_attr_cont.ac.match = sas_rphy_match;
733 transport_container_register(&i->rphy_attr_cont);
734
735 i->f = ft;
736
737 count = 0;
738 i->host_attrs[count] = NULL;
739
740 count = 0;
741 SETUP_PORT_ATTRIBUTE(initiator_port_protocols);
742 SETUP_PORT_ATTRIBUTE(target_port_protocols);
743 SETUP_PORT_ATTRIBUTE(device_type);
744 SETUP_PORT_ATTRIBUTE(sas_address);
745 SETUP_PORT_ATTRIBUTE(phy_identifier);
746 SETUP_PORT_ATTRIBUTE(port_identifier);
747 SETUP_PORT_ATTRIBUTE(negotiated_linkrate);
748 SETUP_PORT_ATTRIBUTE(minimum_linkrate_hw);
749 SETUP_PORT_ATTRIBUTE(minimum_linkrate);
750 SETUP_PORT_ATTRIBUTE(maximum_linkrate_hw);
751 SETUP_PORT_ATTRIBUTE(maximum_linkrate);
752 i->phy_attrs[count] = NULL;
753
754 count = 0;
755 SETUP_RPORT_ATTRIBUTE(rphy_initiator_port_protocols);
756 SETUP_RPORT_ATTRIBUTE(rphy_target_port_protocols);
757 SETUP_RPORT_ATTRIBUTE(rphy_device_type);
758 SETUP_RPORT_ATTRIBUTE(rphy_sas_address);
759 SETUP_RPORT_ATTRIBUTE(rphy_phy_identifier);
760 i->rphy_attrs[count] = NULL;
761
762 return &i->t;
763}
764EXPORT_SYMBOL(sas_attach_transport);
765
766/**
767 * sas_release_transport -- release SAS transport template instance
768 * @t: transport template instance
769 */
770void sas_release_transport(struct scsi_transport_template *t)
771{
772 struct sas_internal *i = to_sas_internal(t);
773
774 transport_container_unregister(&i->t.host_attrs);
775 transport_container_unregister(&i->phy_attr_cont);
776 transport_container_unregister(&i->rphy_attr_cont);
777
778 kfree(i);
779}
780EXPORT_SYMBOL(sas_release_transport);
781
782static __init int sas_transport_init(void)
783{
784 int error;
785
786 error = transport_class_register(&sas_host_class);
787 if (error)
788 goto out;
789 error = transport_class_register(&sas_phy_class);
790 if (error)
791 goto out_unregister_transport;
792 error = transport_class_register(&sas_rphy_class);
793 if (error)
794 goto out_unregister_phy;
795
796 return 0;
797
798 out_unregister_phy:
799 transport_class_unregister(&sas_phy_class);
800 out_unregister_transport:
801 transport_class_unregister(&sas_host_class);
802 out:
803 return error;
804
805}
806
807static void __exit sas_transport_exit(void)
808{
809 transport_class_unregister(&sas_host_class);
810 transport_class_unregister(&sas_phy_class);
811 transport_class_unregister(&sas_rphy_class);
812}
813
814MODULE_AUTHOR("Christoph Hellwig");
815MODULE_DESCRIPTION("SAS Transphy Attributes");
816MODULE_LICENSE("GPL");
817
818module_init(sas_transport_init);
819module_exit(sas_transport_exit);