diff options
Diffstat (limited to 'drivers/scsi/scsi_transport_sas.c')
-rw-r--r-- | drivers/scsi/scsi_transport_sas.c | 58 |
1 files changed, 38 insertions, 20 deletions
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index edabbd05d258..a3e0b7bc2d7b 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | #include <linux/string.h> | 30 | #include <linux/string.h> |
31 | 31 | ||
32 | #include <scsi/scsi.h> | ||
32 | #include <scsi/scsi_device.h> | 33 | #include <scsi/scsi_device.h> |
33 | #include <scsi/scsi_host.h> | 34 | #include <scsi/scsi_host.h> |
34 | #include <scsi/scsi_transport.h> | 35 | #include <scsi/scsi_transport.h> |
@@ -62,7 +63,7 @@ struct sas_internal { | |||
62 | 63 | ||
63 | struct sas_host_attrs { | 64 | struct sas_host_attrs { |
64 | struct list_head rphy_list; | 65 | struct list_head rphy_list; |
65 | spinlock_t lock; | 66 | struct mutex lock; |
66 | u32 next_target_id; | 67 | u32 next_target_id; |
67 | }; | 68 | }; |
68 | #define to_sas_host_attrs(host) ((struct sas_host_attrs *)(host)->shost_data) | 69 | #define to_sas_host_attrs(host) ((struct sas_host_attrs *)(host)->shost_data) |
@@ -165,7 +166,7 @@ static int sas_host_setup(struct transport_container *tc, struct device *dev, | |||
165 | struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); | 166 | struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); |
166 | 167 | ||
167 | INIT_LIST_HEAD(&sas_host->rphy_list); | 168 | INIT_LIST_HEAD(&sas_host->rphy_list); |
168 | spin_lock_init(&sas_host->lock); | 169 | mutex_init(&sas_host->lock); |
169 | sas_host->next_target_id = 0; | 170 | sas_host->next_target_id = 0; |
170 | return 0; | 171 | return 0; |
171 | } | 172 | } |
@@ -626,7 +627,7 @@ int sas_rphy_add(struct sas_rphy *rphy) | |||
626 | transport_add_device(&rphy->dev); | 627 | transport_add_device(&rphy->dev); |
627 | transport_configure_device(&rphy->dev); | 628 | transport_configure_device(&rphy->dev); |
628 | 629 | ||
629 | spin_lock(&sas_host->lock); | 630 | mutex_lock(&sas_host->lock); |
630 | list_add_tail(&rphy->list, &sas_host->rphy_list); | 631 | list_add_tail(&rphy->list, &sas_host->rphy_list); |
631 | if (identify->device_type == SAS_END_DEVICE && | 632 | if (identify->device_type == SAS_END_DEVICE && |
632 | (identify->target_port_protocols & | 633 | (identify->target_port_protocols & |
@@ -634,10 +635,10 @@ int sas_rphy_add(struct sas_rphy *rphy) | |||
634 | rphy->scsi_target_id = sas_host->next_target_id++; | 635 | rphy->scsi_target_id = sas_host->next_target_id++; |
635 | else | 636 | else |
636 | rphy->scsi_target_id = -1; | 637 | rphy->scsi_target_id = -1; |
637 | spin_unlock(&sas_host->lock); | 638 | mutex_unlock(&sas_host->lock); |
638 | 639 | ||
639 | if (rphy->scsi_target_id != -1) { | 640 | if (rphy->scsi_target_id != -1) { |
640 | scsi_scan_target(&rphy->dev, parent->number, | 641 | scsi_scan_target(&rphy->dev, parent->port_identifier, |
641 | rphy->scsi_target_id, ~0, 0); | 642 | rphy->scsi_target_id, ~0, 0); |
642 | } | 643 | } |
643 | 644 | ||
@@ -661,9 +662,9 @@ void sas_rphy_free(struct sas_rphy *rphy) | |||
661 | struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent); | 662 | struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent); |
662 | struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); | 663 | struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); |
663 | 664 | ||
664 | spin_lock(&sas_host->lock); | 665 | mutex_lock(&sas_host->lock); |
665 | list_del(&rphy->list); | 666 | list_del(&rphy->list); |
666 | spin_unlock(&sas_host->lock); | 667 | mutex_unlock(&sas_host->lock); |
667 | 668 | ||
668 | transport_destroy_device(&rphy->dev); | 669 | transport_destroy_device(&rphy->dev); |
669 | put_device(rphy->dev.parent); | 670 | put_device(rphy->dev.parent); |
@@ -687,15 +688,27 @@ sas_rphy_delete(struct sas_rphy *rphy) | |||
687 | struct Scsi_Host *shost = dev_to_shost(parent->dev.parent); | 688 | struct Scsi_Host *shost = dev_to_shost(parent->dev.parent); |
688 | struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); | 689 | struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); |
689 | 690 | ||
690 | scsi_remove_target(dev); | 691 | switch (rphy->identify.device_type) { |
692 | case SAS_END_DEVICE: | ||
693 | scsi_remove_target(dev); | ||
694 | break; | ||
695 | case SAS_EDGE_EXPANDER_DEVICE: | ||
696 | case SAS_FANOUT_EXPANDER_DEVICE: | ||
697 | device_for_each_child(dev, NULL, do_sas_phy_delete); | ||
698 | break; | ||
699 | default: | ||
700 | break; | ||
701 | } | ||
691 | 702 | ||
692 | transport_remove_device(dev); | 703 | transport_remove_device(dev); |
693 | device_del(dev); | 704 | device_del(dev); |
694 | transport_destroy_device(dev); | 705 | transport_destroy_device(dev); |
695 | 706 | ||
696 | spin_lock(&sas_host->lock); | 707 | mutex_lock(&sas_host->lock); |
697 | list_del(&rphy->list); | 708 | list_del(&rphy->list); |
698 | spin_unlock(&sas_host->lock); | 709 | mutex_unlock(&sas_host->lock); |
710 | |||
711 | parent->rphy = NULL; | ||
699 | 712 | ||
700 | put_device(&parent->dev); | 713 | put_device(&parent->dev); |
701 | } | 714 | } |
@@ -719,23 +732,28 @@ EXPORT_SYMBOL(scsi_is_sas_rphy); | |||
719 | * SCSI scan helper | 732 | * SCSI scan helper |
720 | */ | 733 | */ |
721 | 734 | ||
722 | static struct device *sas_target_parent(struct Scsi_Host *shost, | 735 | static int sas_user_scan(struct Scsi_Host *shost, uint channel, |
723 | int channel, uint id) | 736 | uint id, uint lun) |
724 | { | 737 | { |
725 | struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); | 738 | struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); |
726 | struct sas_rphy *rphy; | 739 | struct sas_rphy *rphy; |
727 | struct device *dev = NULL; | ||
728 | 740 | ||
729 | spin_lock(&sas_host->lock); | 741 | mutex_lock(&sas_host->lock); |
730 | list_for_each_entry(rphy, &sas_host->rphy_list, list) { | 742 | list_for_each_entry(rphy, &sas_host->rphy_list, list) { |
731 | struct sas_phy *parent = dev_to_phy(rphy->dev.parent); | 743 | struct sas_phy *parent = dev_to_phy(rphy->dev.parent); |
732 | if (parent->number == channel && | 744 | |
733 | rphy->scsi_target_id == id) | 745 | if (rphy->scsi_target_id == -1) |
734 | dev = &rphy->dev; | 746 | continue; |
747 | |||
748 | if ((channel == SCAN_WILD_CARD || channel == parent->port_identifier) && | ||
749 | (id == SCAN_WILD_CARD || id == rphy->scsi_target_id)) { | ||
750 | scsi_scan_target(&rphy->dev, parent->port_identifier, | ||
751 | rphy->scsi_target_id, lun, 1); | ||
752 | } | ||
735 | } | 753 | } |
736 | spin_unlock(&sas_host->lock); | 754 | mutex_unlock(&sas_host->lock); |
737 | 755 | ||
738 | return dev; | 756 | return 0; |
739 | } | 757 | } |
740 | 758 | ||
741 | 759 | ||
@@ -780,7 +798,7 @@ sas_attach_transport(struct sas_function_template *ft) | |||
780 | return NULL; | 798 | return NULL; |
781 | memset(i, 0, sizeof(struct sas_internal)); | 799 | memset(i, 0, sizeof(struct sas_internal)); |
782 | 800 | ||
783 | i->t.target_parent = sas_target_parent; | 801 | i->t.user_scan = sas_user_scan; |
784 | 802 | ||
785 | i->t.host_attrs.ac.attrs = &i->host_attrs[0]; | 803 | i->t.host_attrs.ac.attrs = &i->host_attrs[0]; |
786 | i->t.host_attrs.ac.class = &sas_host_class.class; | 804 | i->t.host_attrs.ac.class = &sas_host_class.class; |