ac4a53a019c06a1bb8b7564ad38e3f5dc3d7dd81
[powerpc.git] / drivers / scsi / scsi_transport_sas.c
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
40 struct 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
61 struct 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)                   \
82 static ssize_t                                                  \
83 get_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)                  \
101 static ssize_t                                                  \
102 get_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
118 static 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 };
127 sas_bitfield_name_search(device_type, sas_device_type_names)
128
129
130 static 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 };
139 sas_bitfield_name_match(protocol, sas_protocol_names)
140
141 static 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 };
152 sas_bitfield_name_search(linkspeed, sas_linkspeed_names)
153
154
155 /*
156  * SAS host attributes
157  */
158
159 static 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
170 static DECLARE_TRANSPORT_CLASS(sas_host_class,
171                 "sas_host", sas_host_setup, NULL, NULL);
172
173 static 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
193 static 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  */
207 void sas_remove_host(struct Scsi_Host *shost)
208 {
209         device_for_each_child(&shost->shost_gendev, NULL, do_sas_phy_delete);
210 }
211 EXPORT_SYMBOL(sas_remove_host);
212
213
214 /*
215  * SAS Port attributes
216  */
217
218 #define sas_phy_show_simple(field, name, format_string, cast)           \
219 static ssize_t                                                          \
220 show_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)) \
229 static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL)
230
231 #define sas_phy_show_protocol(field, name)                              \
232 static ssize_t                                                          \
233 show_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)                              \
244 static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL)
245
246 #define sas_phy_show_linkspeed(field)                                   \
247 static ssize_t                                                          \
248 show_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)                                   \
257 static CLASS_DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL)
258
259 static ssize_t
260 show_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
269 static CLASS_DEVICE_ATTR(device_type, S_IRUGO, show_sas_device_type, NULL);
270
271 sas_phy_protocol_attr(identify.initiator_port_protocols,
272                 initiator_port_protocols);
273 sas_phy_protocol_attr(identify.target_port_protocols,
274                 target_port_protocols);
275 sas_phy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n",
276                 unsigned long long);
277 sas_phy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8);
278 sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", u8);
279 sas_phy_linkspeed_attr(negotiated_linkrate);
280 sas_phy_linkspeed_attr(minimum_linkrate_hw);
281 sas_phy_linkspeed_attr(minimum_linkrate);
282 sas_phy_linkspeed_attr(maximum_linkrate_hw);
283 sas_phy_linkspeed_attr(maximum_linkrate);
284
285
286 static DECLARE_TRANSPORT_CLASS(sas_phy_class,
287                 "sas_phy", NULL, NULL, NULL);
288
289 static 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
308 static 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  */
328 struct 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 }
351 EXPORT_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  */
359 int 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 }
371 EXPORT_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  */
383 void 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 }
391 EXPORT_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  */
400 void
401 sas_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 }
413 EXPORT_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  */
422 int scsi_is_sas_phy(const struct device *dev)
423 {
424         return dev->release == sas_phy_release;
425 }
426 EXPORT_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)          \
433 static ssize_t                                                          \
434 show_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))        \
443 static SAS_CLASS_DEVICE_ATTR(rphy, name, S_IRUGO,                       \
444                 show_sas_rphy_##name, NULL)
445
446 #define sas_rphy_show_protocol(field, name)                             \
447 static ssize_t                                                          \
448 show_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)                             \
459 static SAS_CLASS_DEVICE_ATTR(rphy, name, S_IRUGO,                       \
460                 show_sas_rphy_##name, NULL)
461
462 static ssize_t
463 show_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
473 static SAS_CLASS_DEVICE_ATTR(rphy, device_type, S_IRUGO,
474                 show_sas_rphy_device_type, NULL);
475
476 sas_rphy_protocol_attr(identify.initiator_port_protocols,
477                 initiator_port_protocols);
478 sas_rphy_protocol_attr(identify.target_port_protocols, target_port_protocols);
479 sas_rphy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n",
480                 unsigned long long);
481 sas_rphy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8);
482
483 static DECLARE_TRANSPORT_CLASS(sas_rphy_class,
484                 "sas_rphy", NULL, NULL, NULL);
485
486 static 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
505 static 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  */
522 struct 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 }
543 EXPORT_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  */
551 int 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 }
586 EXPORT_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  */
599 void 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 }
614 EXPORT_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  */
622 void
623 sas_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 }
643 EXPORT_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  */
652 int scsi_is_sas_rphy(const struct device *dev)
653 {
654         return dev->release == sas_rphy_release;
655 }
656 EXPORT_SYMBOL(scsi_is_sas_rphy);
657
658
659 /*
660  * SCSI scan helper
661  */
662
663 static 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  */
706 struct scsi_transport_template *
707 sas_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 }
764 EXPORT_SYMBOL(sas_attach_transport);
765
766 /**
767  * sas_release_transport  --  release SAS transport template instance
768  * @t:          transport template instance
769  */
770 void 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 }
780 EXPORT_SYMBOL(sas_release_transport);
781
782 static __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
807 static 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
814 MODULE_AUTHOR("Christoph Hellwig");
815 MODULE_DESCRIPTION("SAS Transphy Attributes");
816 MODULE_LICENSE("GPL");
817
818 module_init(sas_transport_init);
819 module_exit(sas_transport_exit);