diff options
author | James Bottomley <James.Bottomley@steeleye.com> | 2006-06-28 12:22:50 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2006-06-28 12:40:54 -0400 |
commit | 65c92b09acf0218b64f1c7ba4fdabeb8b732c876 (patch) | |
tree | 16569cf6039b7e4e810c710f91179292a847fd45 /drivers/scsi/scsi_transport_sas.c | |
parent | 2076eb6ab8339bf09620a0160be3607bbbb61a50 (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>
Diffstat (limited to 'drivers/scsi/scsi_transport_sas.c')
-rw-r--r-- | drivers/scsi/scsi_transport_sas.c | 371 |
1 files changed, 333 insertions, 38 deletions
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 | ||
175 | static int do_sas_phy_delete(struct device *dev, void *data) | 175 | static 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 | */ | ||
192 | void 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 | } | ||
197 | EXPORT_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 | */ |
189 | void sas_remove_host(struct Scsi_Host *shost) | 206 | void 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 | } |
193 | EXPORT_SYMBOL(sas_remove_host); | 210 | EXPORT_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, | |||
310 | sas_phy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n", | 327 | sas_phy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n", |
311 | unsigned long long); | 328 | unsigned long long); |
312 | sas_phy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8); | 329 | sas_phy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8); |
313 | sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", u8); | 330 | //sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", u8); |
314 | sas_phy_linkspeed_attr(negotiated_linkrate); | 331 | sas_phy_linkspeed_attr(negotiated_linkrate); |
315 | sas_phy_linkspeed_attr(minimum_linkrate_hw); | 332 | sas_phy_linkspeed_attr(minimum_linkrate_hw); |
316 | sas_phy_linkspeed_attr(minimum_linkrate); | 333 | sas_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) | |||
464 | EXPORT_SYMBOL(scsi_is_sas_phy); | 482 | EXPORT_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) \ | ||
488 | static ssize_t \ | ||
489 | show_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)) \ | ||
498 | static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_port_##name, NULL) | ||
499 | |||
500 | sas_port_simple_attr(num_phys, num_phys, "%d\n", int); | ||
501 | |||
502 | static DECLARE_TRANSPORT_CLASS(sas_port_class, | ||
503 | "sas_port", NULL, NULL, NULL); | ||
504 | |||
505 | static 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 | |||
525 | static 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 | |||
535 | static 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 | |||
542 | static 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 | */ | ||
560 | struct 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 | } | ||
591 | EXPORT_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 | */ | ||
600 | int 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 | } | ||
617 | EXPORT_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 | */ | ||
629 | void sas_port_free(struct sas_port *port) | ||
630 | { | ||
631 | transport_destroy_device(&port->dev); | ||
632 | put_device(&port->dev); | ||
633 | } | ||
634 | EXPORT_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 | */ | ||
643 | void 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 | } | ||
666 | EXPORT_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 | */ | ||
675 | int scsi_is_sas_port(const struct device *dev) | ||
676 | { | ||
677 | return dev->release == sas_port_release; | ||
678 | } | ||
679 | EXPORT_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 | */ | ||
693 | void 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 | } | ||
716 | EXPORT_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 | */ | ||
726 | void 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 | } | ||
734 | EXPORT_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 | */ |
770 | struct sas_rphy *sas_end_device_alloc(struct sas_phy *parent) | 1040 | struct 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 | */ |
801 | struct sas_rphy *sas_expander_alloc(struct sas_phy *parent, | 1076 | struct 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 | */ |
838 | int sas_rphy_add(struct sas_rphy *rphy) | 1113 | int 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 | |||
910 | sas_rphy_delete(struct sas_rphy *rphy) | 1185 | sas_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); |