aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Bottomley <James.Bottomley@steeleye.com>2006-06-28 12:22:50 -0400
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2006-06-28 12:40:54 -0400
commit65c92b09acf0218b64f1c7ba4fdabeb8b732c876 (patch)
tree16569cf6039b7e4e810c710f91179292a847fd45
parent2076eb6ab8339bf09620a0160be3607bbbb61a50 (diff)
[SCSI] scsi_transport_sas: introduce a sas_port entity
this patch introduces a port object, separates out ports and phys, with ports becoming the primary objects of the tree. Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
-rw-r--r--drivers/scsi/scsi_sas_internal.h10
-rw-r--r--drivers/scsi/scsi_transport_sas.c371
-rw-r--r--include/scsi/scsi_transport_sas.h37
3 files changed, 372 insertions, 46 deletions
diff --git a/drivers/scsi/scsi_sas_internal.h b/drivers/scsi/scsi_sas_internal.h
index d76e6e3d8ca5..e1edab45a37b 100644
--- a/drivers/scsi/scsi_sas_internal.h
+++ b/drivers/scsi/scsi_sas_internal.h
@@ -2,7 +2,8 @@
2#define _SCSI_SAS_INTERNAL_H 2#define _SCSI_SAS_INTERNAL_H
3 3
4#define SAS_HOST_ATTRS 0 4#define SAS_HOST_ATTRS 0
5#define SAS_PORT_ATTRS 17 5#define SAS_PHY_ATTRS 17
6#define SAS_PORT_ATTRS 1
6#define SAS_RPORT_ATTRS 7 7#define SAS_RPORT_ATTRS 7
7#define SAS_END_DEV_ATTRS 3 8#define SAS_END_DEV_ATTRS 3
8#define SAS_EXPANDER_ATTRS 7 9#define SAS_EXPANDER_ATTRS 7
@@ -13,12 +14,14 @@ struct sas_internal {
13 struct sas_domain_function_template *dft; 14 struct sas_domain_function_template *dft;
14 15
15 struct class_device_attribute private_host_attrs[SAS_HOST_ATTRS]; 16 struct class_device_attribute private_host_attrs[SAS_HOST_ATTRS];
16 struct class_device_attribute private_phy_attrs[SAS_PORT_ATTRS]; 17 struct class_device_attribute private_phy_attrs[SAS_PHY_ATTRS];
18 struct class_device_attribute private_port_attrs[SAS_PORT_ATTRS];
17 struct class_device_attribute private_rphy_attrs[SAS_RPORT_ATTRS]; 19 struct class_device_attribute private_rphy_attrs[SAS_RPORT_ATTRS];
18 struct class_device_attribute private_end_dev_attrs[SAS_END_DEV_ATTRS]; 20 struct class_device_attribute private_end_dev_attrs[SAS_END_DEV_ATTRS];
19 struct class_device_attribute private_expander_attrs[SAS_EXPANDER_ATTRS]; 21 struct class_device_attribute private_expander_attrs[SAS_EXPANDER_ATTRS];
20 22
21 struct transport_container phy_attr_cont; 23 struct transport_container phy_attr_cont;
24 struct transport_container port_attr_cont;
22 struct transport_container rphy_attr_cont; 25 struct transport_container rphy_attr_cont;
23 struct transport_container end_dev_attr_cont; 26 struct transport_container end_dev_attr_cont;
24 struct transport_container expander_attr_cont; 27 struct transport_container expander_attr_cont;
@@ -28,7 +31,8 @@ struct sas_internal {
28 * needed by scsi_sysfs.c 31 * needed by scsi_sysfs.c
29 */ 32 */
30 struct class_device_attribute *host_attrs[SAS_HOST_ATTRS + 1]; 33 struct class_device_attribute *host_attrs[SAS_HOST_ATTRS + 1];
31 struct class_device_attribute *phy_attrs[SAS_PORT_ATTRS + 1]; 34 struct class_device_attribute *phy_attrs[SAS_PHY_ATTRS + 1];
35 struct class_device_attribute *port_attrs[SAS_PORT_ATTRS + 1];
32 struct class_device_attribute *rphy_attrs[SAS_RPORT_ATTRS + 1]; 36 struct class_device_attribute *rphy_attrs[SAS_RPORT_ATTRS + 1];
33 struct class_device_attribute *end_dev_attrs[SAS_END_DEV_ATTRS + 1]; 37 struct class_device_attribute *end_dev_attrs[SAS_END_DEV_ATTRS + 1];
34 struct class_device_attribute *expander_attrs[SAS_EXPANDER_ATTRS + 1]; 38 struct class_device_attribute *expander_attrs[SAS_EXPANDER_ATTRS + 1];
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index 1fe6b2d01853..dd075627e605 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -174,12 +174,29 @@ static int sas_host_match(struct attribute_container *cont,
174 174
175static int do_sas_phy_delete(struct device *dev, void *data) 175static int do_sas_phy_delete(struct device *dev, void *data)
176{ 176{
177 if (scsi_is_sas_phy(dev)) 177 int pass = (int)(unsigned long)data;
178
179 if (pass == 0 && scsi_is_sas_port(dev))
180 sas_port_delete(dev_to_sas_port(dev));
181 else if (pass == 1 && scsi_is_sas_phy(dev))
178 sas_phy_delete(dev_to_phy(dev)); 182 sas_phy_delete(dev_to_phy(dev));
179 return 0; 183 return 0;
180} 184}
181 185
182/** 186/**
187 * sas_remove_children -- tear down a devices SAS data structures
188 * @dev: device belonging to the sas object
189 *
190 * Removes all SAS PHYs and remote PHYs for a given object
191 */
192void sas_remove_children(struct device *dev)
193{
194 device_for_each_child(dev, (void *)0, do_sas_phy_delete);
195 device_for_each_child(dev, (void *)1, do_sas_phy_delete);
196}
197EXPORT_SYMBOL(sas_remove_children);
198
199/**
183 * sas_remove_host -- tear down a Scsi_Host's SAS data structures 200 * sas_remove_host -- tear down a Scsi_Host's SAS data structures
184 * @shost: Scsi Host that is torn down 201 * @shost: Scsi Host that is torn down
185 * 202 *
@@ -188,13 +205,13 @@ static int do_sas_phy_delete(struct device *dev, void *data)
188 */ 205 */
189void sas_remove_host(struct Scsi_Host *shost) 206void sas_remove_host(struct Scsi_Host *shost)
190{ 207{
191 device_for_each_child(&shost->shost_gendev, NULL, do_sas_phy_delete); 208 sas_remove_children(&shost->shost_gendev);
192} 209}
193EXPORT_SYMBOL(sas_remove_host); 210EXPORT_SYMBOL(sas_remove_host);
194 211
195 212
196/* 213/*
197 * SAS Port attributes 214 * SAS Phy attributes
198 */ 215 */
199 216
200#define sas_phy_show_simple(field, name, format_string, cast) \ 217#define sas_phy_show_simple(field, name, format_string, cast) \
@@ -310,7 +327,7 @@ sas_phy_protocol_attr(identify.target_port_protocols,
310sas_phy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n", 327sas_phy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n",
311 unsigned long long); 328 unsigned long long);
312sas_phy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8); 329sas_phy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8);
313sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", u8); 330//sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", u8);
314sas_phy_linkspeed_attr(negotiated_linkrate); 331sas_phy_linkspeed_attr(negotiated_linkrate);
315sas_phy_linkspeed_attr(minimum_linkrate_hw); 332sas_phy_linkspeed_attr(minimum_linkrate_hw);
316sas_phy_linkspeed_attr(minimum_linkrate); 333sas_phy_linkspeed_attr(minimum_linkrate);
@@ -378,9 +395,10 @@ struct sas_phy *sas_phy_alloc(struct device *parent, int number)
378 device_initialize(&phy->dev); 395 device_initialize(&phy->dev);
379 phy->dev.parent = get_device(parent); 396 phy->dev.parent = get_device(parent);
380 phy->dev.release = sas_phy_release; 397 phy->dev.release = sas_phy_release;
398 INIT_LIST_HEAD(&phy->port_siblings);
381 if (scsi_is_sas_expander_device(parent)) { 399 if (scsi_is_sas_expander_device(parent)) {
382 struct sas_rphy *rphy = dev_to_rphy(parent); 400 struct sas_rphy *rphy = dev_to_rphy(parent);
383 sprintf(phy->dev.bus_id, "phy-%d-%d:%d", shost->host_no, 401 sprintf(phy->dev.bus_id, "phy-%d:%d:%d", shost->host_no,
384 rphy->scsi_target_id, number); 402 rphy->scsi_target_id, number);
385 } else 403 } else
386 sprintf(phy->dev.bus_id, "phy-%d:%d", shost->host_no, number); 404 sprintf(phy->dev.bus_id, "phy-%d:%d", shost->host_no, number);
@@ -440,8 +458,8 @@ sas_phy_delete(struct sas_phy *phy)
440{ 458{
441 struct device *dev = &phy->dev; 459 struct device *dev = &phy->dev;
442 460
443 if (phy->rphy) 461 /* this happens if the phy is still part of a port when deleted */
444 sas_rphy_delete(phy->rphy); 462 BUG_ON(!list_empty(&phy->port_siblings));
445 463
446 transport_remove_device(dev); 464 transport_remove_device(dev);
447 device_del(dev); 465 device_del(dev);
@@ -464,6 +482,258 @@ int scsi_is_sas_phy(const struct device *dev)
464EXPORT_SYMBOL(scsi_is_sas_phy); 482EXPORT_SYMBOL(scsi_is_sas_phy);
465 483
466/* 484/*
485 * SAS Port attributes
486 */
487#define sas_port_show_simple(field, name, format_string, cast) \
488static ssize_t \
489show_sas_port_##name(struct class_device *cdev, char *buf) \
490{ \
491 struct sas_port *port = transport_class_to_sas_port(cdev); \
492 \
493 return snprintf(buf, 20, format_string, cast port->field); \
494}
495
496#define sas_port_simple_attr(field, name, format_string, type) \
497 sas_port_show_simple(field, name, format_string, (type)) \
498static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_port_##name, NULL)
499
500sas_port_simple_attr(num_phys, num_phys, "%d\n", int);
501
502static DECLARE_TRANSPORT_CLASS(sas_port_class,
503 "sas_port", NULL, NULL, NULL);
504
505static int sas_port_match(struct attribute_container *cont, struct device *dev)
506{
507 struct Scsi_Host *shost;
508 struct sas_internal *i;
509
510 if (!scsi_is_sas_port(dev))
511 return 0;
512 shost = dev_to_shost(dev->parent);
513
514 if (!shost->transportt)
515 return 0;
516 if (shost->transportt->host_attrs.ac.class !=
517 &sas_host_class.class)
518 return 0;
519
520 i = to_sas_internal(shost->transportt);
521 return &i->port_attr_cont.ac == cont;
522}
523
524
525static void sas_port_release(struct device *dev)
526{
527 struct sas_port *port = dev_to_sas_port(dev);
528
529 BUG_ON(!list_empty(&port->phy_list));
530
531 put_device(dev->parent);
532 kfree(port);
533}
534
535static void sas_port_create_link(struct sas_port *port,
536 struct sas_phy *phy)
537{
538 sysfs_create_link(&port->dev.kobj, &phy->dev.kobj, phy->dev.bus_id);
539 sysfs_create_link(&phy->dev.kobj, &port->dev.kobj, "port");
540}
541
542static void sas_port_delete_link(struct sas_port *port,
543 struct sas_phy *phy)
544{
545 sysfs_remove_link(&port->dev.kobj, phy->dev.bus_id);
546 sysfs_remove_link(&phy->dev.kobj, "port");
547}
548
549/** sas_port_alloc - allocate and initialize a SAS port structure
550 *
551 * @parent: parent device
552 * @port_id: port number
553 *
554 * Allocates a SAS port structure. It will be added to the device tree
555 * below the device specified by @parent which must be either a Scsi_Host
556 * or a sas_expander_device.
557 *
558 * Returns %NULL on error
559 */
560struct sas_port *sas_port_alloc(struct device *parent, int port_id)
561{
562 struct Scsi_Host *shost = dev_to_shost(parent);
563 struct sas_port *port;
564
565 port = kzalloc(sizeof(*port), GFP_KERNEL);
566 if (!port)
567 return NULL;
568
569 port->port_identifier = port_id;
570
571 device_initialize(&port->dev);
572
573 port->dev.parent = get_device(parent);
574 port->dev.release = sas_port_release;
575
576 mutex_init(&port->phy_list_mutex);
577 INIT_LIST_HEAD(&port->phy_list);
578
579 if (scsi_is_sas_expander_device(parent)) {
580 struct sas_rphy *rphy = dev_to_rphy(parent);
581 sprintf(port->dev.bus_id, "port-%d:%d:%d", shost->host_no,
582 rphy->scsi_target_id, port->port_identifier);
583 } else
584 sprintf(port->dev.bus_id, "port-%d:%d", shost->host_no,
585 port->port_identifier);
586
587 transport_setup_device(&port->dev);
588
589 return port;
590}
591EXPORT_SYMBOL(sas_port_alloc);
592
593/**
594 * sas_port_add - add a SAS port to the device hierarchy
595 *
596 * @port: port to be added
597 *
598 * publishes a port to the rest of the system
599 */
600int sas_port_add(struct sas_port *port)
601{
602 int error;
603
604 /* No phys should be added until this is made visible */
605 BUG_ON(!list_empty(&port->phy_list));
606
607 error = device_add(&port->dev);
608
609 if (error)
610 return error;
611
612 transport_add_device(&port->dev);
613 transport_configure_device(&port->dev);
614
615 return 0;
616}
617EXPORT_SYMBOL(sas_port_add);
618
619/**
620 * sas_port_free -- free a SAS PORT
621 * @port: SAS PORT to free
622 *
623 * Frees the specified SAS PORT.
624 *
625 * Note:
626 * This function must only be called on a PORT that has not
627 * sucessfully been added using sas_port_add().
628 */
629void sas_port_free(struct sas_port *port)
630{
631 transport_destroy_device(&port->dev);
632 put_device(&port->dev);
633}
634EXPORT_SYMBOL(sas_port_free);
635
636/**
637 * sas_port_delete -- remove SAS PORT
638 * @port: SAS PORT to remove
639 *
640 * Removes the specified SAS PORT. If the SAS PORT has an
641 * associated phys, unlink them from the port as well.
642 */
643void sas_port_delete(struct sas_port *port)
644{
645 struct device *dev = &port->dev;
646 struct sas_phy *phy, *tmp_phy;
647
648 if (port->rphy) {
649 sas_rphy_delete(port->rphy);
650 port->rphy = NULL;
651 }
652
653 mutex_lock(&port->phy_list_mutex);
654 list_for_each_entry_safe(phy, tmp_phy, &port->phy_list,
655 port_siblings) {
656 sas_port_delete_link(port, phy);
657 list_del_init(&phy->port_siblings);
658 }
659 mutex_unlock(&port->phy_list_mutex);
660
661 transport_remove_device(dev);
662 device_del(dev);
663 transport_destroy_device(dev);
664 put_device(dev);
665}
666EXPORT_SYMBOL(sas_port_delete);
667
668/**
669 * scsi_is_sas_port -- check if a struct device represents a SAS port
670 * @dev: device to check
671 *
672 * Returns:
673 * %1 if the device represents a SAS Port, %0 else
674 */
675int scsi_is_sas_port(const struct device *dev)
676{
677 return dev->release == sas_port_release;
678}
679EXPORT_SYMBOL(scsi_is_sas_port);
680
681/**
682 * sas_port_add_phy - add another phy to a port to form a wide port
683 * @port: port to add the phy to
684 * @phy: phy to add
685 *
686 * When a port is initially created, it is empty (has no phys). All
687 * ports must have at least one phy to operated, and all wide ports
688 * must have at least two. The current code makes no difference
689 * between ports and wide ports, but the only object that can be
690 * connected to a remote device is a port, so ports must be formed on
691 * all devices with phys if they're connected to anything.
692 */
693void sas_port_add_phy(struct sas_port *port, struct sas_phy *phy)
694{
695 mutex_lock(&port->phy_list_mutex);
696 if (unlikely(!list_empty(&phy->port_siblings))) {
697 /* make sure we're already on this port */
698 struct sas_phy *tmp;
699
700 list_for_each_entry(tmp, &port->phy_list, port_siblings)
701 if (tmp == phy)
702 break;
703 /* If this trips, you added a phy that was already
704 * part of a different port */
705 if (unlikely(tmp != phy)) {
706 dev_printk(KERN_ERR, &port->dev, "trying to add phy %s fails: it's already part of another port\n", phy->dev.bus_id);
707 BUG();
708 }
709 } else {
710 sas_port_create_link(port, phy);
711 list_add_tail(&phy->port_siblings, &port->phy_list);
712 port->num_phys++;
713 }
714 mutex_unlock(&port->phy_list_mutex);
715}
716EXPORT_SYMBOL(sas_port_add_phy);
717
718/**
719 * sas_port_delete_phy - remove a phy from a port or wide port
720 * @port: port to remove the phy from
721 * @phy: phy to remove
722 *
723 * This operation is used for tearing down ports again. It must be
724 * done to every port or wide port before calling sas_port_delete.
725 */
726void sas_port_delete_phy(struct sas_port *port, struct sas_phy *phy)
727{
728 mutex_lock(&port->phy_list_mutex);
729 sas_port_delete_link(port, phy);
730 list_del_init(&phy->port_siblings);
731 port->num_phys--;
732 mutex_unlock(&port->phy_list_mutex);
733}
734EXPORT_SYMBOL(sas_port_delete_phy);
735
736/*
467 * SAS remote PHY attributes. 737 * SAS remote PHY attributes.
468 */ 738 */
469 739
@@ -767,7 +1037,7 @@ static void sas_rphy_initialize(struct sas_rphy *rphy)
767 * Returns: 1037 * Returns:
768 * SAS PHY allocated or %NULL if the allocation failed. 1038 * SAS PHY allocated or %NULL if the allocation failed.
769 */ 1039 */
770struct sas_rphy *sas_end_device_alloc(struct sas_phy *parent) 1040struct sas_rphy *sas_end_device_alloc(struct sas_port *parent)
771{ 1041{
772 struct Scsi_Host *shost = dev_to_shost(&parent->dev); 1042 struct Scsi_Host *shost = dev_to_shost(&parent->dev);
773 struct sas_end_device *rdev; 1043 struct sas_end_device *rdev;
@@ -780,8 +1050,13 @@ struct sas_rphy *sas_end_device_alloc(struct sas_phy *parent)
780 device_initialize(&rdev->rphy.dev); 1050 device_initialize(&rdev->rphy.dev);
781 rdev->rphy.dev.parent = get_device(&parent->dev); 1051 rdev->rphy.dev.parent = get_device(&parent->dev);
782 rdev->rphy.dev.release = sas_end_device_release; 1052 rdev->rphy.dev.release = sas_end_device_release;
783 sprintf(rdev->rphy.dev.bus_id, "end_device-%d:%d-%d", 1053 if (scsi_is_sas_expander_device(parent->dev.parent)) {
784 shost->host_no, parent->port_identifier, parent->number); 1054 struct sas_rphy *rphy = dev_to_rphy(parent->dev.parent);
1055 sprintf(rdev->rphy.dev.bus_id, "end_device-%d:%d:%d",
1056 shost->host_no, rphy->scsi_target_id, parent->port_identifier);
1057 } else
1058 sprintf(rdev->rphy.dev.bus_id, "end_device-%d:%d",
1059 shost->host_no, parent->port_identifier);
785 rdev->rphy.identify.device_type = SAS_END_DEVICE; 1060 rdev->rphy.identify.device_type = SAS_END_DEVICE;
786 sas_rphy_initialize(&rdev->rphy); 1061 sas_rphy_initialize(&rdev->rphy);
787 transport_setup_device(&rdev->rphy.dev); 1062 transport_setup_device(&rdev->rphy.dev);
@@ -798,7 +1073,7 @@ EXPORT_SYMBOL(sas_end_device_alloc);
798 * Returns: 1073 * Returns:
799 * SAS PHY allocated or %NULL if the allocation failed. 1074 * SAS PHY allocated or %NULL if the allocation failed.
800 */ 1075 */
801struct sas_rphy *sas_expander_alloc(struct sas_phy *parent, 1076struct sas_rphy *sas_expander_alloc(struct sas_port *parent,
802 enum sas_device_type type) 1077 enum sas_device_type type)
803{ 1078{
804 struct Scsi_Host *shost = dev_to_shost(&parent->dev); 1079 struct Scsi_Host *shost = dev_to_shost(&parent->dev);
@@ -837,7 +1112,7 @@ EXPORT_SYMBOL(sas_expander_alloc);
837 */ 1112 */
838int sas_rphy_add(struct sas_rphy *rphy) 1113int sas_rphy_add(struct sas_rphy *rphy)
839{ 1114{
840 struct sas_phy *parent = dev_to_phy(rphy->dev.parent); 1115 struct sas_port *parent = dev_to_sas_port(rphy->dev.parent);
841 struct Scsi_Host *shost = dev_to_shost(parent->dev.parent); 1116 struct Scsi_Host *shost = dev_to_shost(parent->dev.parent);
842 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 1117 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
843 struct sas_identify *identify = &rphy->identify; 1118 struct sas_identify *identify = &rphy->identify;
@@ -910,7 +1185,7 @@ void
910sas_rphy_delete(struct sas_rphy *rphy) 1185sas_rphy_delete(struct sas_rphy *rphy)
911{ 1186{
912 struct device *dev = &rphy->dev; 1187 struct device *dev = &rphy->dev;
913 struct sas_phy *parent = dev_to_phy(dev->parent); 1188 struct sas_port *parent = dev_to_sas_port(dev->parent);
914 struct Scsi_Host *shost = dev_to_shost(parent->dev.parent); 1189 struct Scsi_Host *shost = dev_to_shost(parent->dev.parent);
915 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); 1190 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
916 1191
@@ -920,7 +1195,7 @@ sas_rphy_delete(struct sas_rphy *rphy)
920 break; 1195 break;
921 case SAS_EDGE_EXPANDER_DEVICE: 1196 case SAS_EDGE_EXPANDER_DEVICE:
922 case SAS_FANOUT_EXPANDER_DEVICE: 1197 case SAS_FANOUT_EXPANDER_DEVICE:
923 device_for_each_child(dev, NULL, do_sas_phy_delete); 1198 sas_remove_children(dev);
924 break; 1199 break;
925 default: 1200 default:
926 break; 1201 break;
@@ -967,7 +1242,7 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel,
967 1242
968 mutex_lock(&sas_host->lock); 1243 mutex_lock(&sas_host->lock);
969 list_for_each_entry(rphy, &sas_host->rphy_list, list) { 1244 list_for_each_entry(rphy, &sas_host->rphy_list, list) {
970 struct sas_phy *parent = dev_to_phy(rphy->dev.parent); 1245 struct sas_port *parent = dev_to_sas_port(rphy->dev.parent);
971 1246
972 if (rphy->identify.device_type != SAS_END_DEVICE || 1247 if (rphy->identify.device_type != SAS_END_DEVICE ||
973 rphy->scsi_target_id == -1) 1248 rphy->scsi_target_id == -1)
@@ -1003,16 +1278,19 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel,
1003#define SETUP_OPTIONAL_RPORT_ATTRIBUTE(field, func) \ 1278#define SETUP_OPTIONAL_RPORT_ATTRIBUTE(field, func) \
1004 SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, i->f->func) 1279 SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, i->f->func)
1005 1280
1006#define SETUP_PORT_ATTRIBUTE(field) \ 1281#define SETUP_PHY_ATTRIBUTE(field) \
1007 SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, 1) 1282 SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, 1)
1008 1283
1009#define SETUP_OPTIONAL_PORT_ATTRIBUTE(field, func) \ 1284#define SETUP_PORT_ATTRIBUTE(field) \
1285 SETUP_TEMPLATE(port_attrs, field, S_IRUGO, 1)
1286
1287#define SETUP_OPTIONAL_PHY_ATTRIBUTE(field, func) \
1010 SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, i->f->func) 1288 SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, i->f->func)
1011 1289
1012#define SETUP_PORT_ATTRIBUTE_WRONLY(field) \ 1290#define SETUP_PHY_ATTRIBUTE_WRONLY(field) \
1013 SETUP_TEMPLATE(phy_attrs, field, S_IWUGO, 1) 1291 SETUP_TEMPLATE(phy_attrs, field, S_IWUGO, 1)
1014 1292
1015#define SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(field, func) \ 1293#define SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(field, func) \
1016 SETUP_TEMPLATE(phy_attrs, field, S_IWUGO, i->f->func) 1294 SETUP_TEMPLATE(phy_attrs, field, S_IWUGO, i->f->func)
1017 1295
1018#define SETUP_END_DEV_ATTRIBUTE(field) \ 1296#define SETUP_END_DEV_ATTRIBUTE(field) \
@@ -1048,6 +1326,11 @@ sas_attach_transport(struct sas_function_template *ft)
1048 i->phy_attr_cont.ac.match = sas_phy_match; 1326 i->phy_attr_cont.ac.match = sas_phy_match;
1049 transport_container_register(&i->phy_attr_cont); 1327 transport_container_register(&i->phy_attr_cont);
1050 1328
1329 i->port_attr_cont.ac.class = &sas_port_class.class;
1330 i->port_attr_cont.ac.attrs = &i->port_attrs[0];
1331 i->port_attr_cont.ac.match = sas_port_match;
1332 transport_container_register(&i->port_attr_cont);
1333
1051 i->rphy_attr_cont.ac.class = &sas_rphy_class.class; 1334 i->rphy_attr_cont.ac.class = &sas_rphy_class.class;
1052 i->rphy_attr_cont.ac.attrs = &i->rphy_attrs[0]; 1335 i->rphy_attr_cont.ac.attrs = &i->rphy_attrs[0];
1053 i->rphy_attr_cont.ac.match = sas_rphy_match; 1336 i->rphy_attr_cont.ac.match = sas_rphy_match;
@@ -1066,30 +1349,35 @@ sas_attach_transport(struct sas_function_template *ft)
1066 i->f = ft; 1349 i->f = ft;
1067 1350
1068 count = 0; 1351 count = 0;
1352 SETUP_PORT_ATTRIBUTE(num_phys);
1069 i->host_attrs[count] = NULL; 1353 i->host_attrs[count] = NULL;
1070 1354
1071 count = 0; 1355 count = 0;
1072 SETUP_PORT_ATTRIBUTE(initiator_port_protocols); 1356 SETUP_PHY_ATTRIBUTE(initiator_port_protocols);
1073 SETUP_PORT_ATTRIBUTE(target_port_protocols); 1357 SETUP_PHY_ATTRIBUTE(target_port_protocols);
1074 SETUP_PORT_ATTRIBUTE(device_type); 1358 SETUP_PHY_ATTRIBUTE(device_type);
1075 SETUP_PORT_ATTRIBUTE(sas_address); 1359 SETUP_PHY_ATTRIBUTE(sas_address);
1076 SETUP_PORT_ATTRIBUTE(phy_identifier); 1360 SETUP_PHY_ATTRIBUTE(phy_identifier);
1077 SETUP_PORT_ATTRIBUTE(port_identifier); 1361 //SETUP_PHY_ATTRIBUTE(port_identifier);
1078 SETUP_PORT_ATTRIBUTE(negotiated_linkrate); 1362 SETUP_PHY_ATTRIBUTE(negotiated_linkrate);
1079 SETUP_PORT_ATTRIBUTE(minimum_linkrate_hw); 1363 SETUP_PHY_ATTRIBUTE(minimum_linkrate_hw);
1080 SETUP_PORT_ATTRIBUTE(minimum_linkrate); 1364 SETUP_PHY_ATTRIBUTE(minimum_linkrate);
1081 SETUP_PORT_ATTRIBUTE(maximum_linkrate_hw); 1365 SETUP_PHY_ATTRIBUTE(maximum_linkrate_hw);
1082 SETUP_PORT_ATTRIBUTE(maximum_linkrate); 1366 SETUP_PHY_ATTRIBUTE(maximum_linkrate);
1083 1367
1084 SETUP_PORT_ATTRIBUTE(invalid_dword_count); 1368 SETUP_PHY_ATTRIBUTE(invalid_dword_count);
1085 SETUP_PORT_ATTRIBUTE(running_disparity_error_count); 1369 SETUP_PHY_ATTRIBUTE(running_disparity_error_count);
1086 SETUP_PORT_ATTRIBUTE(loss_of_dword_sync_count); 1370 SETUP_PHY_ATTRIBUTE(loss_of_dword_sync_count);
1087 SETUP_PORT_ATTRIBUTE(phy_reset_problem_count); 1371 SETUP_PHY_ATTRIBUTE(phy_reset_problem_count);
1088 SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(link_reset, phy_reset); 1372 SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(link_reset, phy_reset);
1089 SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(hard_reset, phy_reset); 1373 SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(hard_reset, phy_reset);
1090 i->phy_attrs[count] = NULL; 1374 i->phy_attrs[count] = NULL;
1091 1375
1092 count = 0; 1376 count = 0;
1377 SETUP_PORT_ATTRIBUTE(num_phys);
1378 i->port_attrs[count] = NULL;
1379
1380 count = 0;
1093 SETUP_RPORT_ATTRIBUTE(rphy_initiator_port_protocols); 1381 SETUP_RPORT_ATTRIBUTE(rphy_initiator_port_protocols);
1094 SETUP_RPORT_ATTRIBUTE(rphy_target_port_protocols); 1382 SETUP_RPORT_ATTRIBUTE(rphy_target_port_protocols);
1095 SETUP_RPORT_ATTRIBUTE(rphy_device_type); 1383 SETUP_RPORT_ATTRIBUTE(rphy_device_type);
@@ -1131,6 +1419,7 @@ void sas_release_transport(struct scsi_transport_template *t)
1131 1419
1132 transport_container_unregister(&i->t.host_attrs); 1420 transport_container_unregister(&i->t.host_attrs);
1133 transport_container_unregister(&i->phy_attr_cont); 1421 transport_container_unregister(&i->phy_attr_cont);
1422 transport_container_unregister(&i->port_attr_cont);
1134 transport_container_unregister(&i->rphy_attr_cont); 1423 transport_container_unregister(&i->rphy_attr_cont);
1135 transport_container_unregister(&i->end_dev_attr_cont); 1424 transport_container_unregister(&i->end_dev_attr_cont);
1136 transport_container_unregister(&i->expander_attr_cont); 1425 transport_container_unregister(&i->expander_attr_cont);
@@ -1149,9 +1438,12 @@ static __init int sas_transport_init(void)
1149 error = transport_class_register(&sas_phy_class); 1438 error = transport_class_register(&sas_phy_class);
1150 if (error) 1439 if (error)
1151 goto out_unregister_transport; 1440 goto out_unregister_transport;
1152 error = transport_class_register(&sas_rphy_class); 1441 error = transport_class_register(&sas_port_class);
1153 if (error) 1442 if (error)
1154 goto out_unregister_phy; 1443 goto out_unregister_phy;
1444 error = transport_class_register(&sas_rphy_class);
1445 if (error)
1446 goto out_unregister_port;
1155 error = transport_class_register(&sas_end_dev_class); 1447 error = transport_class_register(&sas_end_dev_class);
1156 if (error) 1448 if (error)
1157 goto out_unregister_rphy; 1449 goto out_unregister_rphy;
@@ -1165,6 +1457,8 @@ static __init int sas_transport_init(void)
1165 transport_class_unregister(&sas_end_dev_class); 1457 transport_class_unregister(&sas_end_dev_class);
1166 out_unregister_rphy: 1458 out_unregister_rphy:
1167 transport_class_unregister(&sas_rphy_class); 1459 transport_class_unregister(&sas_rphy_class);
1460 out_unregister_port:
1461 transport_class_unregister(&sas_port_class);
1168 out_unregister_phy: 1462 out_unregister_phy:
1169 transport_class_unregister(&sas_phy_class); 1463 transport_class_unregister(&sas_phy_class);
1170 out_unregister_transport: 1464 out_unregister_transport:
@@ -1178,6 +1472,7 @@ static void __exit sas_transport_exit(void)
1178{ 1472{
1179 transport_class_unregister(&sas_host_class); 1473 transport_class_unregister(&sas_host_class);
1180 transport_class_unregister(&sas_phy_class); 1474 transport_class_unregister(&sas_phy_class);
1475 transport_class_unregister(&sas_port_class);
1181 transport_class_unregister(&sas_rphy_class); 1476 transport_class_unregister(&sas_rphy_class);
1182 transport_class_unregister(&sas_end_dev_class); 1477 transport_class_unregister(&sas_end_dev_class);
1183 transport_class_unregister(&sas_expander_class); 1478 transport_class_unregister(&sas_expander_class);
diff --git a/include/scsi/scsi_transport_sas.h b/include/scsi/scsi_transport_sas.h
index 93cfb4bf4211..e3c503cd175e 100644
--- a/include/scsi/scsi_transport_sas.h
+++ b/include/scsi/scsi_transport_sas.h
@@ -3,6 +3,7 @@
3 3
4#include <linux/transport_class.h> 4#include <linux/transport_class.h>
5#include <linux/types.h> 5#include <linux/types.h>
6#include <linux/mutex.h>
6 7
7struct scsi_transport_template; 8struct scsi_transport_template;
8struct sas_rphy; 9struct sas_rphy;
@@ -55,7 +56,6 @@ struct sas_phy {
55 enum sas_linkrate minimum_linkrate; 56 enum sas_linkrate minimum_linkrate;
56 enum sas_linkrate maximum_linkrate_hw; 57 enum sas_linkrate maximum_linkrate_hw;
57 enum sas_linkrate maximum_linkrate; 58 enum sas_linkrate maximum_linkrate;
58 u8 port_identifier;
59 59
60 /* internal state */ 60 /* internal state */
61 unsigned int local_attached : 1; 61 unsigned int local_attached : 1;
@@ -66,8 +66,8 @@ struct sas_phy {
66 u32 loss_of_dword_sync_count; 66 u32 loss_of_dword_sync_count;
67 u32 phy_reset_problem_count; 67 u32 phy_reset_problem_count;
68 68
69 /* the other end of the link */ 69 /* for the list of phys belonging to a port */
70 struct sas_rphy *rphy; 70 struct list_head port_siblings;
71}; 71};
72 72
73#define dev_to_phy(d) \ 73#define dev_to_phy(d) \
@@ -124,6 +124,24 @@ struct sas_expander_device {
124#define rphy_to_expander_device(r) \ 124#define rphy_to_expander_device(r) \
125 container_of((r), struct sas_expander_device, rphy) 125 container_of((r), struct sas_expander_device, rphy)
126 126
127struct sas_port {
128 struct device dev;
129
130 u8 port_identifier;
131 int num_phys;
132
133 /* the other end of the link */
134 struct sas_rphy *rphy;
135
136 struct mutex phy_list_mutex;
137 struct list_head phy_list;
138};
139
140#define dev_to_sas_port(d) \
141 container_of((d), struct sas_port, dev)
142#define transport_class_to_sas_port(cdev) \
143 dev_to_sas_port((cdev)->dev)
144
127/* The functions by which the transport class and the driver communicate */ 145/* The functions by which the transport class and the driver communicate */
128struct sas_function_template { 146struct sas_function_template {
129 int (*get_linkerrors)(struct sas_phy *); 147 int (*get_linkerrors)(struct sas_phy *);
@@ -133,6 +151,7 @@ struct sas_function_template {
133}; 151};
134 152
135 153
154void sas_remove_children(struct device *);
136extern void sas_remove_host(struct Scsi_Host *); 155extern void sas_remove_host(struct Scsi_Host *);
137 156
138extern struct sas_phy *sas_phy_alloc(struct device *, int); 157extern struct sas_phy *sas_phy_alloc(struct device *, int);
@@ -141,13 +160,21 @@ extern int sas_phy_add(struct sas_phy *);
141extern void sas_phy_delete(struct sas_phy *); 160extern void sas_phy_delete(struct sas_phy *);
142extern int scsi_is_sas_phy(const struct device *); 161extern int scsi_is_sas_phy(const struct device *);
143 162
144extern struct sas_rphy *sas_end_device_alloc(struct sas_phy *); 163extern struct sas_rphy *sas_end_device_alloc(struct sas_port *);
145extern struct sas_rphy *sas_expander_alloc(struct sas_phy *, enum sas_device_type); 164extern struct sas_rphy *sas_expander_alloc(struct sas_port *, enum sas_device_type);
146void sas_rphy_free(struct sas_rphy *); 165void sas_rphy_free(struct sas_rphy *);
147extern int sas_rphy_add(struct sas_rphy *); 166extern int sas_rphy_add(struct sas_rphy *);
148extern void sas_rphy_delete(struct sas_rphy *); 167extern void sas_rphy_delete(struct sas_rphy *);
149extern int scsi_is_sas_rphy(const struct device *); 168extern int scsi_is_sas_rphy(const struct device *);
150 169
170struct sas_port *sas_port_alloc(struct device *, int);
171int sas_port_add(struct sas_port *);
172void sas_port_free(struct sas_port *);
173void sas_port_delete(struct sas_port *);
174void sas_port_add_phy(struct sas_port *, struct sas_phy *);
175void sas_port_delete_phy(struct sas_port *, struct sas_phy *);
176int scsi_is_sas_port(const struct device *);
177
151extern struct scsi_transport_template * 178extern struct scsi_transport_template *
152sas_attach_transport(struct sas_function_template *); 179sas_attach_transport(struct sas_function_template *);
153extern void sas_release_transport(struct scsi_transport_template *); 180extern void sas_release_transport(struct scsi_transport_template *);