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 | |
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>
-rw-r--r-- | drivers/scsi/scsi_sas_internal.h | 10 | ||||
-rw-r--r-- | drivers/scsi/scsi_transport_sas.c | 371 | ||||
-rw-r--r-- | include/scsi/scsi_transport_sas.h | 37 |
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 | ||
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); |
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 | ||
7 | struct scsi_transport_template; | 8 | struct scsi_transport_template; |
8 | struct sas_rphy; | 9 | struct 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 | ||
127 | struct 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 */ |
128 | struct sas_function_template { | 146 | struct 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 | ||
154 | void sas_remove_children(struct device *); | ||
136 | extern void sas_remove_host(struct Scsi_Host *); | 155 | extern void sas_remove_host(struct Scsi_Host *); |
137 | 156 | ||
138 | extern struct sas_phy *sas_phy_alloc(struct device *, int); | 157 | extern struct sas_phy *sas_phy_alloc(struct device *, int); |
@@ -141,13 +160,21 @@ extern int sas_phy_add(struct sas_phy *); | |||
141 | extern void sas_phy_delete(struct sas_phy *); | 160 | extern void sas_phy_delete(struct sas_phy *); |
142 | extern int scsi_is_sas_phy(const struct device *); | 161 | extern int scsi_is_sas_phy(const struct device *); |
143 | 162 | ||
144 | extern struct sas_rphy *sas_end_device_alloc(struct sas_phy *); | 163 | extern struct sas_rphy *sas_end_device_alloc(struct sas_port *); |
145 | extern struct sas_rphy *sas_expander_alloc(struct sas_phy *, enum sas_device_type); | 164 | extern struct sas_rphy *sas_expander_alloc(struct sas_port *, enum sas_device_type); |
146 | void sas_rphy_free(struct sas_rphy *); | 165 | void sas_rphy_free(struct sas_rphy *); |
147 | extern int sas_rphy_add(struct sas_rphy *); | 166 | extern int sas_rphy_add(struct sas_rphy *); |
148 | extern void sas_rphy_delete(struct sas_rphy *); | 167 | extern void sas_rphy_delete(struct sas_rphy *); |
149 | extern int scsi_is_sas_rphy(const struct device *); | 168 | extern int scsi_is_sas_rphy(const struct device *); |
150 | 169 | ||
170 | struct sas_port *sas_port_alloc(struct device *, int); | ||
171 | int sas_port_add(struct sas_port *); | ||
172 | void sas_port_free(struct sas_port *); | ||
173 | void sas_port_delete(struct sas_port *); | ||
174 | void sas_port_add_phy(struct sas_port *, struct sas_phy *); | ||
175 | void sas_port_delete_phy(struct sas_port *, struct sas_phy *); | ||
176 | int scsi_is_sas_port(const struct device *); | ||
177 | |||
151 | extern struct scsi_transport_template * | 178 | extern struct scsi_transport_template * |
152 | sas_attach_transport(struct sas_function_template *); | 179 | sas_attach_transport(struct sas_function_template *); |
153 | extern void sas_release_transport(struct scsi_transport_template *); | 180 | extern void sas_release_transport(struct scsi_transport_template *); |